這篇帶大家按照官方入門指南來體驗(yàn)下Quantopian的魅力,文章中會涉及到一些平臺中常用的API房午,大家可以先有個初步印象,用的時候再去查文檔即可。文章最后會實(shí)現(xiàn)一個簡單的均值回歸的策略昧互,好了,寬客動手不動口,開始我們的旅程伟桅!
交易算法框架
在Quantopian中敞掘,交易算法是一段Python腳本,其中包含了幾個關(guān)鍵的函數(shù)
-
initialize()
程序啟動時調(diào)用的函數(shù)楣铁,用于處理啟動時需要的一次性邏輯玖雁,需要context(上下文對象)作為輸入。
context是一個增強(qiáng)的Python字典盖腕,用于存儲回測或交易中的一些狀態(tài)與有效數(shù)據(jù)赫冬,它作為算法中的共享區(qū)域浓镜,在各個函數(shù)中均可訪問其內(nèi)容(使用context.鍵值的方式)。 -
handle_data()
按照自定義的周期劲厌,定時調(diào)用膛薛,一般在其中處理當(dāng)前周期中需要處理的訂單,context與data是函數(shù)的兩個參數(shù)脊僚。
data是用于存放一些API方法的對象相叁。 -
before_trading_start()
每交易日開盤前調(diào)用的函數(shù),通常用于選定當(dāng)天待交易的股票辽幌,入?yún)⑴chandle_data一樣增淹,也為context與data兩個對象。
一個最基礎(chǔ)的算法框架如下:
def initialize(context):
# 啟動后需要處理的一次性邏輯
def handle_data(context, data):
# 定時執(zhí)行乌企,處理當(dāng)前周期中待處理訂單
def before_trading_start(context, data):
# 開盤前執(zhí)行虑润,選定當(dāng)天待交易股票
整體框架基本可以模擬了我們平日里的交易操作,很容易理解加酵。對于框架有初步了解后拳喻,我們再繼續(xù)前進(jìn)一小步,如何獲購買一只股票呢猪腕?首先我們要獲取到這只股票
獲取證券信息
平臺提供了sid()函數(shù)冗澈,這個函數(shù)會根據(jù)輸入返回一只股票在平臺中的唯一ID,且是始終不變的陋葡。
比如你想獲取到蘋果公司的股票亚亲,只需要在代碼區(qū)域調(diào)用sid函數(shù),并在入?yún)⒗镙斎牍善焙喎QAAPL腐缤,編輯器就會智能地給出相應(yīng)提示捌归。
獲取之后一般都會存放到context對象中,供之后的邏輯使用
def initialize(context):
context.aapl = sid(24)
def handle_data(context, data):
print context.aapl
下單
下單平臺提供了幾種不同的函數(shù)岭粤,這個點(diǎn)后續(xù)再展開詳述惜索,這篇文章我們以order_target_percent()這個為例進(jìn)行說明,order_target_percent函數(shù)需要兩個參數(shù)剃浇,sid(證券ID)與target_percent(投資比例巾兆,分母為可用頭寸)
**注:
可用頭寸=現(xiàn)金賬戶+敞口頭寸(open position)
敞口頭寸應(yīng)該為當(dāng)日買賣差價
**
如果用可用頭寸的50%去做多蘋果,代碼如下
order_target_percent(sid(24), 0.50)
而如果用可用頭寸的50%去做空偿渡,代碼如下
order_target_percent(sid(24), -0.50)
獲取證券信息
在下單前臼寄,策略可能需要根據(jù)歷史及當(dāng)前該證券的信息進(jìn)行分析,data對象提供了幾個快捷的函數(shù)供使用溜宽。
- data.current() 獲取當(dāng)前信息
需要兩個參數(shù)吉拳,第一個參數(shù)為證券sid或一個證券sid列表,第二個參數(shù)為你需要的信息字段适揉,目前支持的有價格(price)留攒、開盤價(open)煤惩、收盤價(close)、最高價(high)炼邀、最低價(low)與交易量(volume)魄揉。
例如:
data.current(sid(24), 'price') #獲取蘋果的當(dāng)前價格
data.current([sid(24), sid(46631)], 'price') 獲取蘋果與谷歌的當(dāng)前股價
data.current([sid(24), sid(46631)], ['low', 'high'])獲取蘋果與谷歌截止當(dāng)前的最高最低價
- data.can_trade() 該證券能否交易
需要傳入證券sid或證券sid列表 - data.history() 獲取歷史信息
在current參數(shù)的基礎(chǔ)上增加了回看窗口大小(lookback window length)及回看頻率(lookback frequency)的參數(shù)
hist = data.history(sid(24), 'price', 10, '1d')#獲取蘋果過去十天的價格,頻率為每天
mean_price = hist.mean()
#注:獲取歷史價格的時候拭宁,會先返回當(dāng)前的價格洛退,及前9天的日中收盤價,所以如果你希望獲取前十天的均價杰标,先取11天兵怯,然后丟棄掉最新的一條。
data.history(sid(8554), 'price', 11, '1d')[:-1].mean()
注: data.current()與data.history()返回的均為pandas的DataFrame結(jié)構(gòu)腔剂,pandas這個python科學(xué)庫后續(xù)會專門一系列說明
自定義調(diào)度
可以根據(jù)自己需要的周期媒区,靈活地定義自己需要的定時處理邏輯函數(shù),參數(shù)中包含自定義函數(shù)名掸犬、日期規(guī)則與實(shí)踐規(guī)則袜漩,
#在每周第一天開盤后一小時,已目前可用的10%買入蘋果股票湾碎。
def initialize(context):
context.aapl = sid(24)
schedule_function(func=open_positions,
data_rules=date_rules.week_start(),
time_rules=time_rules.market_open(hours=1)
def open_positions(context, data):
order_target_percent(context.aapl, 0.10)
查詢當(dāng)前持倉
Quantopian在context中內(nèi)置了portfolio對象宙攻,持倉存儲在context.portfolio.positions中,positions可以看做sid為鍵介褥,Postion對象為值的一個字典粘优。我們可以使用for...in語法進(jìn)行循環(huán)處理:
#清盤所有持倉
for security in context.portfolio.positions:
order_target_percent(security, 0)
繪制變量
平臺提供了record()方法幫助你將自己關(guān)注的變量繪制成時間序列圖,可以方便的監(jiān)控關(guān)心的變量呻顽。
def initialize(context):
context.aapl = sid(24)
schedule_function(record_vars, date_rules.every_day(), time_rules.market_close())
def record_vars(context, data):
long_count = 0
short_count = 0
for position in context.portfolio.positions.itervalues():
if position.amount > 0:
long_count += 1
if position.amount < 0:
short_count += 1
# 繪制圖表
record(num_long=long_count, num_short=short_count)
重新編譯算法后,可直觀地展現(xiàn)每日收盤空頭/多頭的時間序列圖丹墨。
滑點(diǎn)與傭金
滑點(diǎn)與傭金都屬于交易成本的范疇廊遍,對于算法的實(shí)際表現(xiàn)影響很大
- 滑點(diǎn)
滑點(diǎn)表示由于下單(尤其是大單)對于股價潛在的影響,會導(dǎo)致實(shí)際成交比預(yù)期差的情況贩挣,平臺中集成了多種滑點(diǎn)的策略喉前,下面為默認(rèn)的策略:
# 假設(shè)過去幾分鐘內(nèi)交易量為1000時,限制每次只能下1000*0.025=25的單王财,系統(tǒng)會根據(jù)這個值進(jìn)行拆單
set_slippage(slippage.VolumeShareSlippage(volume_limit=0.025, price_impact=0.1))
- 傭金
可以根據(jù)真實(shí)經(jīng)紀(jì)商的情況設(shè)置傭金費(fèi)率及最小費(fèi)用卵迂。
set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1))
訂單管理
因?yàn)橛唵位径疾皇羌纯坛山坏模耶?dāng)前未成交訂單對于后續(xù)的策略執(zhí)行也有很大的指導(dǎo)意義绒净,所以訂單管理的功能也是至關(guān)重要的见咒。
get_open_orders()函數(shù)幫助我們獲取當(dāng)前已下但尚未成交的訂單
open_orders = get_open_orders()
if context.xtl not in open_orders and data.can_trade(context.xtl):
order_target_percent(context.xtl, 1.0)
動手均值回歸策略
好了,把之前所有的內(nèi)容整合起來挂疆,我們很容易就能實(shí)現(xiàn)一個簡單的均值回歸策略改览。均值回歸策略可以簡單的理解為短期的均值會有一定波動下翎,但隨時間一定會逐步與長期均值趨同。
我們就來實(shí)現(xiàn)這樣一個策略:
如果一個股票10天移動平均高于了其30天移動平均值宝当,我們則認(rèn)為股價一定會下跌视事,反之亦然。
def initialize(context):
#初始化證券池
context.security_list = [sid(5061), sid(7792), sid(1941), sid(24556), sid(1746)]
# 自定義調(diào)度:每周第一交易日開盤時重新計算并執(zhí)行組合重新配置
schedule_function(rebalance,
date_rules.week_start(days_offset=0),
time_rules.market_open())
def compute_weights(context, data):
#計算10日與30日均值
hist = data.history(context.security_list, 'price', 30, '1d')
prices_10 = hist[-10:]
prices_30 = hist
sma_10 = prices_10.mean()
sma_30 = prices_30.mean()
# 加權(quán)計算
raw_weights = (sma_30 - sma_10) / sma_30
normalized_weights = raw_weights / raw_weights.abs().sum()
return normalized_weights
def rebalance(context, data):
# 重置權(quán)重
weights = compute_weights(context, data)
# 組合重新分配
for security in context.security_list:
if data.can_trade(security):
order_target_percent(security, weights[security])
這一篇到這里就結(jié)束了庆揩,是不是覺得很容易上手呢俐东?建議大家去官方教程里克隆策略,自己上手跑一跑订晌,對于量化交易會更有體會虏辫。