{"id":19966682,"url":"https://github.com/truthhun/intertemporal-arbitrage","last_synced_at":"2026-02-01T05:32:38.214Z","repository":{"id":88501708,"uuid":"119639351","full_name":"TruthHun/intertemporal-arbitrage","owner":"TruthHun","description":"跨期套利(期货)，期货的跨期套利策略","archived":false,"fork":false,"pushed_at":"2018-01-31T05:30:38.000Z","size":51,"stargazers_count":54,"open_issues_count":0,"forks_count":23,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-14T13:43:28.077Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.myquant.cn/docs/python_strategyies/107","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TruthHun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-01-31T05:27:28.000Z","updated_at":"2025-03-17T00:28:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"51f3316a-75cc-4f4e-8c2d-7bc421f3b25b","html_url":"https://github.com/TruthHun/intertemporal-arbitrage","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TruthHun/intertemporal-arbitrage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TruthHun%2Fintertemporal-arbitrage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TruthHun%2Fintertemporal-arbitrage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TruthHun%2Fintertemporal-arbitrage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TruthHun%2Fintertemporal-arbitrage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TruthHun","download_url":"https://codeload.github.com/TruthHun/intertemporal-arbitrage/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TruthHun%2Fintertemporal-arbitrage/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28970026,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T04:44:20.970Z","status":"ssl_error","status_checked_at":"2026-02-01T04:44:19.994Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T02:37:33.657Z","updated_at":"2026-02-01T05:32:38.201Z","avatar_url":"https://github.com/TruthHun.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 跨期套利(期货)\n期货的跨期套利策略\n\n## 源码\n```python\n# coding=utf-8\nfrom __future__ import print_function, absolute_import, unicode_literals\nimport numpy as np\nfrom gm.api import *\ntry:\n    import statsmodels.tsa.stattools as ts\nexcept:\n    print('请安装statsmodels库')\n'''\n本策略根据EG两步法(1.序列同阶单整2.OLS残差平稳)判断序列具有协整关系之后(若无协整关系则全平仓位不进行操作)\n通过计算两个真实价格序列回归残差的0.9个标准差上下轨,并在价差突破上轨的时候做空价差,价差突破下轨的时候做多价差\n并在回归至标准差水平内的时候平仓\n回测数据为:SHFE.rb1801和SHFE.rb1805的1min数据\n回测时间为:2017-09-25 08:00:00到2017-10-01 15:00:00\n'''\n# 协整检验的函数\ndef cointegration_test(series01, series02):\n    urt_rb1801 = ts.adfuller(np.array(series01), 1)[1]\n    urt_rb1805 = ts.adfuller(np.array(series01), 1)[1]\n    # 同时平稳或不平稳则差分再次检验\n    if (urt_rb1801 \u003e 0.1 and urt_rb1805 \u003e 0.1) or (urt_rb1801 \u003c 0.1 and urt_rb1805 \u003c 0.1):\n        urt_diff_rb1801 = ts.adfuller(np.diff(np.array(series01)), 1)[1]\n        urt_diff_rb1805 = ts.adfuller(np.diff(np.array(series01), 1))[1]\n        # 同时差分平稳进行OLS回归的残差平稳检验\n        if urt_diff_rb1801 \u003c 0.1 and urt_diff_rb1805 \u003c 0.1:\n            matrix = np.vstack([series02, np.ones(len(series02))]).T\n            beta, c = np.linalg.lstsq(matrix, series01)[0]\n            resid = series01 - beta * series02 - c\n            if ts.adfuller(np.array(resid), 1)[1] \u003e 0.1:\n                result = 0.0\n            else:\n                result = 1.0\n            return beta, c, resid, result\n        else:\n            result = 0.0\n            return 0.0, 0.0, 0.0, result\n    else:\n        result = 0.0\n        return 0.0, 0.0, 0.0, result\ndef init(context):\n    context.goods = ['SHFE.rb1801', 'SHFE.rb1805']\n    # 订阅品种\n    subscribe(symbols=context.goods, frequency='60s', count=801, wait_group=True)\ndef on_bar(context, bars):\n    # 获取过去800个60s的收盘价数据\n    close_01 = context.data(symbol=context.goods[0], frequency='60s', count=801, fields='close')['close'].values\n    close_02 = context.data(symbol=context.goods[1], frequency='60s', count=801, fields='close')['close'].values\n    # 展示两个价格序列的协整检验的结果\n    beta, c, resid, result = cointegration_test(close_01, close_02)\n    # 如果返回协整检验不通过的结果则全平仓位等待\n    if not result:\n        print('协整检验不通过,全平所有仓位')\n        order_close_all()\n        return\n    # 计算残差的标准差上下轨\n    mean = np.mean(resid)\n    up = mean + 0.9 * np.std(resid)\n    down = mean - 0.9 * np.std(resid)\n    # 计算新残差\n    resid_new = close_01[-1] - beta * close_02[-1] - c\n    # 获取rb1801的多空仓位\n    position_01_long = context.account().position(symbol=context.goods[0], side=PositionSide_Long)\n    position_01_short = context.account().position(symbol=context.goods[0], side=PositionSide_Short)\n    if not position_01_long and not position_01_short:\n        # 上穿上轨时做空新残差\n        if resid_new \u003e up:\n            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,\n                                position_side=PositionSide_Short)\n            print(context.goods[0] + '以市价单开空仓1手')\n            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,\n                                position_side=PositionSide_Long)\n            print(context.goods[1] + '以市价单开多仓1手')\n        # 下穿下轨时做多新残差\n        if resid_new \u003c down:\n            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,\n                                position_side=PositionSide_Long)\n            print(context.goods[0], '以市价单开多仓1手')\n            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,\n                                position_side=PositionSide_Short)\n            print(context.goods[1], '以市价单开空仓1手')\n    # 新残差回归时平仓\n    elif position_01_short:\n        if resid_new \u003c= up:\n            order_close_all()\n            print('价格回归,平掉所有仓位')\n        # 突破下轨反向开仓\n        if resid_new \u003c down:\n            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,\n                                position_side=PositionSide_Long)\n            print(context.goods[0], '以市价单开多仓1手')\n            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,\n                                position_side=PositionSide_Short)\n            print(context.goods[1], '以市价单开空仓1手')\n    elif position_01_long:\n        if resid_new \u003e= down:\n            order_close_all()\n            print('价格回归,平所有仓位')\n        # 突破上轨反向开仓\n        if resid_new \u003e up:\n            order_target_volume(symbol=context.goods[0], volume=1, order_type=OrderType_Market,\n                                position_side=PositionSide_Short)\n            print(context.goods[0], '以市价单开空仓1手')\n            order_target_volume(symbol=context.goods[1], volume=1, order_type=OrderType_Market,\n                                position_side=PositionSide_Long)\n            print(context.goods[1], '以市价单开多仓1手')\nif __name__ == '__main__':\n    '''\n    strategy_id策略ID,由系统生成\n    filename文件名,请与本文件名保持一致\n    mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST\n    token绑定计算机的ID,可在系统设置-密钥管理中生成\n    backtest_start_time回测开始时间\n    backtest_end_time回测结束时间\n    backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST\n    backtest_initial_cash回测初始资金\n    backtest_commission_ratio回测佣金比例\n    backtest_slippage_ratio回测滑点比例\n    '''\n    run(strategy_id='strategy_id',\n        filename='main.py',\n        mode=MODE_BACKTEST,\n        token='token_id',\n        backtest_start_time='2017-09-25 08:00:00',\n        backtest_end_time='2017-10-01 16:00:00',\n        backtest_adjust=ADJUST_PREV,\n        backtest_initial_cash=500000,\n        backtest_commission_ratio=0.0001,\n        backtest_slippage_ratio=0.0001)\n```\n\n## 绩效图\n![绩效图](attach.png)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftruthhun%2Fintertemporal-arbitrage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftruthhun%2Fintertemporal-arbitrage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftruthhun%2Fintertemporal-arbitrage/lists"}