
对于那些拥有DTN IQFeed订阅的用户,该服务提供了一种用于获取日内数据的客户机-服务器机制。要实现这一点,需要下载IQLink服务器并在Windows上运行它。不幸的是,除非使用WINE模拟器,否则很难在Mac或Linux上执行此服务器。但是,一旦服务器运行起来,就可以通过套接字连接到它,在套接字处可以查询数据。
在本节中,我们将使用Python套接字接口从2007年1月1日起为一对美国etf获取详细的bar数据。由于美国市场每年大约有252个交易日,每个交易日有6.5小时的交易时间,这将相当于至少65万条数据,每个数据点包括7个数据点: 时间戳、开盘、低、高、收盘、成交量和未平仓头寸。这里选择了SPY和IWM etf下载到CSV。在执行此脚本之前,在Windows中启动IQLink程序:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# iqfeed.py
import sys
import socket
def read_historical_data_socket(sock, recv_buffer=4096):
"""
在缓冲中从套接字读取信息
一次只接收4096字节。
参数:
sock——套接字对象
recv_buffer—每次读取接收的字节数"""
buffer = ""
data = ""
while True:
data = sock.recv(recv_buffer)
buffer += data
# 检查结束消息字符串是否到达
if "!ENDMSG!" in buffer:
break
# 去除结束消息字符串
buffer = buffer[:-12] return buffer
if __name__ == "__main__":
# 定义要下载的服务器主机、端口和符号
host = "127.0.0.1" # Localhost
port = 9100 # Historical data socket port
syms = ["SPY", "IWM"]
# 将每个符号下载到磁盘
for sym in syms:
print "Downloading symbol: %s..." % sym
# 构造IQFeed检索数据所需的消息
message = "HIT,%s,60,20070101 075000,,,093000,160000,1\n" % sym
# 在本地打开到IQFeed服务器的流套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port))
# 发送历史数据请求消息
# 并缓冲数据
sock.sendall(message)data = read_historical_data_socket(sock) sock.close
# 删除所有的结束行和行尾
# 每个记录的逗号分隔符
data = "".join(data.split("\r"))
data = data.replace(",\n","\n")[:-1]
# 将数据流写入磁盘
f = open("%s.csv" % sym, "w")
f.write(data)
f.close()
通过在DTN IQFeed账户中添加订阅选项,可以下载单个期货合约(以及反向调整的连续合约)、期权和指数。DTN IQFeed还提供实时tick流,但是这种形式的数据超出了本书的范围。
清理财务数据
在供应商提供财务数据之后,有必要执行数据清理。不幸的是,这可能是一个艰苦的过程,但却是非常必要的。有许多问题需要解决:不正确的数据、考虑数据聚合和回填。股票和期货合约有其独特的挑战,必须在进行策略研究之前加以处理,包括向后/向前调整、持续合约缝合和公司行动处理。
数据质量
数据供应商的声誉往往取决于其(感知到的)数据质量。简而言之,糟糕或缺失的数据会导致错误的交易信号,从而造成潜在的损失。尽管如此,许多供应商仍然受到数据质量差或不一致的困扰。因此,总是需要进行清洗过程。数据质量差的主要原因是冲突/不正确的数据、多个数据源的不透明聚合和错误纠正(“回填”)。
冲突和不正确的数据——坏数据可以发生在流中的任何地方。在交易所,软件中的漏洞可能导致在匹配交易时出现错误的价格。这将过滤到供应商,然后是贸易商。信誉良好的供应商会试图标记上游的“bad ticks”,并经常将这些点的“纠正”留给交易员。
连续期货合约
在本节中,我们将从回溯测试的角度来讨论对数据提出挑战的期货合约的特征。特别是“连续合同”的概念。我们将概述期货的主要困难,并提供一个Python与pandas的实现,可以部分缓解这些问题。
期货合约概述
期货是买卖双方在未来某一特定日期就一定数量的标的资产订立的一种合同形式。这个日期称为交货日期或到期日。当此日期达到时,买方必须按照合同成立日商定的价格向卖方交付实物标的(或现金等价物)。
实际上,期货交易是在交易所(而不是场外交易)进行的,交易标的的数量和质量都是标准化的。这些价格每天都按市价计算。期货具有令人难以置信的流动性,并被大量用于投机目的。虽然期货经常被用来对冲农产品或工业品的价格,但期货合约可以基于任何有形或无形的基础,如股指、外汇价值利率等。
在CSI数据网站:futures Factsheet上可以找到所有用于不同交易所期货合约的品种代码的详细列表。期货合同和股权之间的主要区别在于,期货合同的有效期限有限。任何时候,同一基础上的各种期货合约都会有不同的到期日。期限最近的合同称为近合同。作为量化交易员,我们面临的问题是,在任何时候,我们都有多个交易合约可供选择。因此,我们面对的是一组重叠的时间序列,而不是像股票或外汇那样的连续流。
本节的目标是概述从这一系列多个系列中构造连续契约流的各种方法,并强调与每种技术相关的权衡。
形成连续期货合同
试图从交付不同的基础合同生成连续合同的主要困难在于,这些合同的交易价格通常不相同。因此,出现了这样的情况:它们不能提供从一个到下一个的平滑拼接。这是由于期货溢价和现货溢价效应。有很多方法可以解决这个问题,我们现在就来讨论一下。
不幸的是,在金融行业中,没有统一的“标准”方法来将期货合约合并在一起。最终选择的方法将在很大程度上取决于采用合同和执行方法的战略。尽管没有单一的方法存在,但有一些常见的方法:
向后/向前(“Panama”)调整方法通过将每个合同转移到相邻的合同,从而使单个交付顺利地连接到相邻的合同,从而缓解了多个合同之间的“差距”。因此,先前合同到期时的开盘价/收盘价是一致的。
巴拿马方法的关键问题包括引入趋势偏差,这将导致价格大幅波动。这可能导致历史契约出现负面数据。此外,由于价值的绝对转移,相对价格差异也有所损失。这意味着返回值的计算很复杂(或者根本不正确)。
比例调整方法类似于处理股票分割的调整方法。旧的结算(收盘价)价格与新的开盘价格之比不是在连续的合约中进行绝对的变动,而是用来按比例调整历史合约的价格。这允许连续流而不中断百分比回报的计算。比例调整的主要问题是,任何依赖绝对价格水平的交易策略也必须进行类似的调整,以执行正确的信号。这是一个有问题且容易出错的过程。因此,这种类型的连续流通常只用于汇总统计分析,而不是直接的回测研究。
滚动/永久序列方法通过在若干天内对每个合同的线性加权比例来创建一个连续合同,以确保每个合同之间的过渡更为平稳。例如,考虑平稳的五天。第一天的价格P1,等于远合同价格的80% (F1)和近合同价格的20% (N1)。同样,第2天的价格是P2 = 0.6×F2 + 0.4×N2。到第五天,P5 = 0.0×F5 + 1.0×N5 = N5,合同就成为了近期价格的延续。
因此,五天之后,合同就顺利地由远转近了。滚转方法的问题在于,它要求所有交易都在5天内进行,这可能会增加交易成本。还有其他不太常见的方法来解决这个问题,但是我们将在这里避免它们。本节的其余部分将集中于实现perpetual series方法,因为它最适合于回测。这是开展战略管道研究的有效途径。
我们将WTI原油“近”和“远”期货合约(品种CL)缝合在一起,以生成一个连续的价格序列。在撰写本文时(2014年1月),近合同为CLF2014(1月),远合同为CLG2014(2月)。为了下载期货数据,我使用了Quandl插件。请确保在您的系统上设置正确的Python虚拟环境,并在终端中输入以下命令安装Quandl包:
pip install Quandl
现在Quandl包已经整合好了,我们需要使用NumPy和pandas来进行翻转构造。创建一个新文件,并输入以下导入语句:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# cont_futures.py
from __future__ import print_function
import datetime
import numpy as np
import pandas as pd
import Quandl
主要工作是在futures_rollover_weights函数中执行的。它需要一个开始日期(最近合同的第一个日期)、合同结算日期字典(到期日期)、合同符号和将合同展期的天数(默认为5天)。下面的注释解释了代码:
def futures_rollover_weights(start_date, expiry_dates,
contracts, rollover_days=5):
"""
这将构造一个包含权重(0.0至1.0)的pandas Dataframe
的合约职位
在展期届满前进行展期最早的合同。
然后这个矩阵可以被乘以
另一个包含每个的固定价格的数据框
产生一个连续的时间序列期货合约。
"""
# 构造一个日期开始的序列
# 从最早的合同开始日期到合同结束
# 最终合同日期
dates = pd.date_range(start_date, expiry_dates[-1], freq=’B’)
# 创建“roll weights”Dataframe,用于存储乘数
# 每个合同(0.0到1.0之间)
roll_weights = pd.DataFrame(np.zeros((len(dates), len(contracts))),
index=dates, columns=contracts)
prev_date = roll_weights.index
# 循环遍历每个契约并为其创建特定权重
# 每个合同取决于结算日期和rollover_days
for i, (item, ex_date) in enumerate(expiry_dates.iteritems()):
if i < len(expiry_dates) - 1:
roll_weights.ix[prev_date:ex_date - pd.offsets.BDay(), item] = 1
roll_rng = pd.date_range(end=ex_date - pd.offsets.BDay(),
periods=rollover_days + 1, freq=’B’)
# 创建一个滚动权重序列(即[0.0,0.2,…,0.8,1.0])
# 用这些来调整每个期货的权重
decay_weights = np.linspace(0, 1, rollover_days + 1)
roll_weights.ix[roll_rng, item] = 1 - decay_weights
roll_weights.ix[roll_rng,
expiry_dates.index[i+1]] = decay_weights
else:
roll_weights.ix[prev_date:, item] = 1
prev_date = ex_date
return roll_weights
既然权重矩阵已经生成,就有可能将其应用于单个时间序列。主函数下载远近契约,为两者创建一个单一的DataFrame,构造滚动加权矩阵,最后生成两个价格的连续序列,并适当加权:
if __name__ == "__main__":
# 下载当前前后(远近)期货合约
# WTI原油,在纽约商品交易所交易,来自Quandl.com。
# 你需要调整合同以反映你当前的远近合同
# 取决于你读这篇文章的时候!
wti_near = Quandl.get("OFDP/FUTURE_CLF2014")
wti_far = Quandl.get("OFDP/FUTURE_CLG2014")
wti = pd.DataFrame({’CLF2014’: wti_near[’Settle’],
’CLG2014’: wti_far[’Settle’]}, index=wti_far.index)
# 为每个合同创建有效期字典
expiry_dates = pd.Series(
{’CLF2014’: datetime.datetime(2013, 12, 19),
’CLG2014’: datetime.datetime(2014, 2, 21)}).order()
# 获得滚动加权矩阵/dataframe
weights = futures_rollover_weights(wti_near.index
,
expiry_dates, wti.columns)
# 构建WTI CL合同的持续期货
wti_cts = (wti * weights).sum(1).dropna()
# 合并后的一系列合同结算价格
print(wti_cts.tail(60))
输出如下:
2013-10-14 102.230
2013-10-15 101.240
2013-10-16 102.330
2013-10-17 100.620
2013-10-18 100.990
2013-10-21 99.760
2013-10-22 98.470
2013-10-23 97.000
2013-10-24 97.240
2013-10-25 97.950
..
..
2013-12-24 99.220
2013-12-26 99.550
2013-12-27 100.320
2013-12-30 99.290
2013-12-31 98.420
2014-01-02 95.440
2014-01-03 93.960
2014-01-06 93.430
2014-01-07 93.670
2014-01-08 92.330
Length: 60, dtype: float64
可以看出,该系列现在是连续的,横跨两个合同。根据您的回测需求,这可以扩展到处理不同年份的多个交付。
【交易学习】
【交易员洞察】
【基础知识】
【货币交易】
【黄金交易】
إخلاء المسؤولية: الآراء الواردة هنا تعبر فقط عن رأي الكاتب، ولا تمثل الموقف الرسمي لـ Followme. لا تتحمل Followme مسؤولية دقة أو اكتمال أو موثوقية المعلومات المُقدمة، ولا تتحمل مسؤولية أي إجراءات تُتخذ بناءً على المحتوى، ما لم يُنص على ذلك صراحةً كتابيًا.

اترك رسالتك الآن