本文中将带领您基于DevelStudio完成一个国内期货全市场的跨期套利监控小程序,并实现日常监控报告生产。
套利,通常指在某种实物资产或金融资产拥有两个价格的情况下,以较低的价格买进,较高的价格卖出,从而获取丰厚的收益。
某支股票同时在伦敦和纽约交易所上市,同股同权,但是在纽约标价10美元,在伦敦却标价12美元,投资者就可以在纽约买进,到伦敦卖出。 又比如在货币交易上进行套利,如借入利息较低的货币为融资,买进高息货币以赚取汇差或利差,例如,日元放款利息长年维持在近乎零的水平,而南非或巴西等国因其通胀严重,利息常年维持在高水平。 如果借入日圆来购买南非币或巴西里拉,在不考虑汇差情况下,也能赚取丰厚的利差。
而跨期套利是套利策略的一种,是在同一期货品种的不同月份合约上建立数量相等、方向相反的交易头寸,最后以对冲或交割方式结束交易、获得收益的方式。 我们以中国期货市场为例,当前有几十种不同类型的合约在交易,而每种合约有多个不同交割月份的独立合约。如何能有效发现市场中可能存在的套利机会?
下面的内容中将带您通过一个Python小程序实现全市场合约的跨期套利监控。
数据准备
在编写市场监控程序之前,您需要先部署DataCenter进行数据采集,收集足够的行情数据。如果您已经完成了DataCenter的部署,可直接跳过并阅读下一小节。
启动DataCenter
$ mkdir /home/thunder-ticks
$ sudo docker run --privileged -d -p 70:80 -v /home/thunder-ticks:/thunder-ticks thundertrader/datacenter:1.81
随后我们登录DataCenter控制面板http://127.0.0.1:70
并配置CTP行情采集插件,即可完成部署。地址http://127.0.0.1:70
就是数据中心的地址,后面小结会用到。
具体的使用方法可以参考文档DataCenter使用文档。
启动DevelStudio
$ mkdir /home/workspace
$ sudo docker --privileged -d run -p 8080:80 -p 8081:81 -p 8082:82 -v /home/workspace:/workspace thundertrader/develstudio:1.81
通过上述命令,我们启动了DevelStudio容器并分别在8080
/8081
/8082
三个端口绑定了VSCode
/Jupyter Notebook
以及Nginx下载目录
,并且将新建的目录/home/workspace
映射到容器中的/workspace
。
具体的使用方法可以参考文档DevelStudio使用文档。
计算价差
完整的代码您可以在https://github.com/thunder-trader/thunder-trader-101
下载。
我们打开http://127.0.0.1:8080/
进入VSCode(默认密码为thunderpass),在/workspace
目录下新建一个名为arbitrage_plot.py
的脚本文件。
首先我们定义一些程序执行的关键参数
REPORT_PATH = "/publish/future_price_diff"
DATA_CENTER = "http://192.168.3.44:70"
CONFIGURATION = """[{"enable":1,"sfit":"a"},{"enable":1,"sfit":"au"},{"enable":1,"sfit":"IF"},{"enable":1,"sfit":"ag"}]"""
其中REPORT_PATH
是我们存储监控报告的地方。在上述启动命令中,DevelStudio默认会在8082端口绑定Nginx下载服务,并且将/publish
目录作为根目录,所以我们只需要将生成的报告文件放置在该目录下,就可以通过http://127.0.0.1:8082/
进行下载查看。
DATA_CENTER
是数据中心的地址,而CONFIGURATION
是期望进行计算的合约类型,您可以将较为关注的合约添加到其中。
首先我们通过read_configuration
函数从配置中读取到需要计算价差的合约类型,例如上述列举的a
/IF
/ag
/au
等。对于每一个合约类型,我们需要找到该合约类型下面的当前所有有效合约。
instrument_ids = []
# Load instrument meta data from /thunder-data/instruments.conf
# This data file will be update every day from thunder-trader.com
instrument_records = pythunder.system.load_instrument_information_from_file("/thunder-data/instruments.config")
# Find all instrument names of this specified future type
pattern = "%s\\d+$" % (future_type)
for name, value in instrument_records.items():
if (re.match(pattern, value.get_instrument_id())):
instrument_ids.append(value.get_unique_name())
我们可以通过load_instrument_information_from_file
函数载入所有合约的信息,该函数的主要原理是读取指定的合约信息文件(/thunder-data/instruments.config
),并解析其中的合约信息。
DevelStudio中的合约信息文件会被日级别周期性从官网更新,确保合约信息的准备性以及实时性。
拿到所有具体合约名称后,我们载入对应的合约Tick行情数据。
for item in instrument_ids:
result[item] = ptu.load_from_data_center(item, start.strftime("%Y%m%d"), end.strftime("%Y%m%d"), DATA_CENTER)
在上述的代码中,load_from_data_center
函数可以实现从数据中心载入数据。
在所有行情数据都被载入之后,我们还无法直接计算价差以及生成报告,因为虽然所有数据都属于同一个合约类型,但是不同交割时间的合约行情数据都是独立记录的。
我们在计算跨期价差之前,需要首先对行情数据进行对齐(align_ticks)。同时,为了让绘制的图标更加直观,我们在1分钟内只采样一个点。
align_ticks
函数可以完成ticks数据相关对齐和采样:
def align_ticks(data):
h = []
names = set(data.keys())
for k, v in data.items():
for tick in v:
heapq.heappush(h, (tick.timestamp, "%s.%s" % (tick.tick_type, tick.instrument_id), tick.last_price, tick.datetime))
heapq.heapify(h)
result = dict()
timestamp = []
window = lambda t : int(t[0] / 60000)
while len(h) != 0:
sample = dict()
tick = heapq.heappop(h)
sample[tick[1]] = tick[2]
window_index = window(tick)
while len(h) != 0 and window(h[0]) == window_index:
tick = heapq.heappop(h)
sample[tick[1]] = tick[2]
for i in names.difference(sample.keys()):
sample[i] = float("nan")
for k, v in sample.items():
if k not in result:
result[k] = []
result[k].append(v)
timestamp.append(window_index * 60000)
return result
基于已经对齐的行情数据,我们计算所有的隔月价差,比如对于RB合约,我们会计算下面的价差:
- price diff of
sfit.future.rb2505
&sfit.future.rb2506
- price diff of
sfit.future.rb2506
&sfit.future.rb2507
- price diff of
sfit.future.rb2507
&sfit.future.rb2508
- price diff of
sfit.future.rb2508
&sfit.future.rb2509
- price diff of
sfit.future.rb2509
&sfit.future.rb2510
- price diff of
sfit.future.rb2510
&sfit.future.rb2511
- price diff of
sfit.future.rb2511
&sfit.future.rb2512
- price diff of
sfit.future.rb2512
&sfit.future.rb2601
- price diff of
sfit.future.rb2601
&sfit.future.rb2602
- price diff of
sfit.future.rb2602
&sfit.future.rb2603
- price diff of
sfit.future.rb2603
&sfit.future.rb2604
完整的代码您可以在https://github.com/thunder-trader/thunder-trader-101
下载。
当程序编辑完成后,我们在Terminal中运行:
python3 /workspace/arbitrage_plot.py
当程序执行完成后,我们可以在/publish
文件夹下面看到所有生成的价差报告。
您也可以在WEB浏览器中直接进行查看,访问http://127.0.0.1:8082/
即可看到/publish
文件夹下面的内容。
定时执行
为了让我们的监控小程序能够每天执行一次,我们执行crontab -e
添加一个定时任务,确保每天上午8:00程序能够自动扫描市场数据并生成最新的报告。
0 8 * * * python3 /workspace/arbitrage_plot.py 1>/dev/null 2>&1
报告分析
白银期货跨期价差。
从图中可以看到白银期货的价差在几个月之内非常稳定,几乎没有大的波动,这也代表白银合约基本不存在跨期套利的机会。
螺纹钢期货跨期价差。
从图中可以看到螺纹钢期货的跨期价差与合约有关,2507合约与2508合约的价差明显存在趋势,不满足套利交易的条件,而2511与2512合约的价差较为稳定,但是存在一定波动,这样的价差可能存在套利的机会。
豆二期货跨期价差
玉米期货跨期价差
豆二期货与玉米期货的价差存在明显的趋势,不适合套利策略。
总结
DevelStudio是一个开放式策略研发环境,在DevelStudio中集成了PyThunder
以及多种常见的数据分析工具箱。欢迎您在www.thunder-trader.com官网下载使用。