聲明:本文策略源碼均來自掘金量化示例策略庫,僅供參考!
一、股票策略
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
importnumpyasnp
fromgm.apiimport*
frompandasimportDataFrame
'''
本策略每隔1個月定時觸發,根據Fama-French三因子模型對每只股票進行回歸,得到其alpha值。
假設Fama-French三因子模型可以完全解釋市場,則alpha為負表明市場低估該股,因此應該買入。
策略思路:
計算市場收益率、個股的賬面市值比和市值,并對后兩個進行了分類,
根據分類得到的組合分別計算其市值加權收益率、SMB和HML.
對各個股票進行回歸(假設無風險收益率等于0)得到alpha值.
選取alpha值小于0并為最小的10只股票進入標的池
平掉不在標的池的股票并等權買入在標的池的股票
回測數據:SHSE.000300的成份股
回測時間:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
definit(context):
# 每月第一個交易日的09:40 定時執行algo任務
schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
print(order_target_percent(symbol='SHSE.600000', percent=0.5, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long))
# 數據滑窗
context.date =20
# 設置開倉的最大資金量
context.ratio =0.8
# 賬面市值比的大/中/小分類
context.BM_BIG =3.0
context.BM_MID =2.0
context.BM_SMA =1.0
# 市值大/小分類
context.MV_BIG =2.0
context.MV_SMA =1.0
# 計算市值加權的收益率,MV為市值的分類,BM為賬目市值比的分類
defmarket_value_weighted(stocks, MV, BM):
? ? select = stocks[(stocks.NEGOTIABLEMV == MV) & (stocks.BM == BM)]
market_value = select['mv'].values
? ? mv_total = np.sum(market_value)
mv_weighted = [mv / mv_totalformvinmarket_value]
stock_return = select['return'].values
# 返回市值加權的收益率的和
? ? return_total = []
foriinrange(len(mv_weighted)):
? ? ? ? return_total.append(mv_weighted[i] * stock_return[i])
? ? return_total = np.sum(return_total)
returnreturn_total
defalgo(context):
# 獲取上一個交易日的日期
last_day = get_previous_trading_date(exchange='SHSE', date=context.now)
# 獲取滬深300成份股
context.stock300 = get_history_constituents(index='SHSE.000300', start_date=last_day,
end_date=last_day)[0]['constituents'].keys()
# 獲取當天有交易的股票
? ? not_suspended = get_history_instruments(symbols=context.stock300, start_date=last_day, end_date=last_day)
not_suspended = [item['symbol']foriteminnot_suspendedifnotitem['is_suspended']]
fin = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended, start_date=last_day, end_date=last_day,
fields='PB,NEGOTIABLEMV', df=True)
# 計算賬面市值比,為P/B的倒數
fin['PB'] = (fin['PB'] **-1)
# 計算市值的50%的分位點,用于后面的分類
size_gate = fin['NEGOTIABLEMV'].quantile(0.50)
# 計算賬面市值比的30%和70%分位點,用于后面的分類
bm_gate = [fin['PB'].quantile(0.30), fin['PB'].quantile(0.70)]
? ? fin.index = fin.symbol
? ? x_return = []
# 對未停牌的股票進行處理
forsymbolinnot_suspended:
# 計算收益率
close = history_n(symbol=symbol, frequency='1d', count=context.date +1, end_time=last_day, fields='close',
skip_suspended=True, fill_missing='Last', adjust=ADJUST_PREV, df=True)['close'].values
stock_return = close[-1] / close[0] -1
pb = fin['PB'][symbol]
market_value = fin['NEGOTIABLEMV'][symbol]
# 獲取[股票代碼. 股票收益率, 賬面市值比的分類, 市值的分類, 流通市值]
ifpb < bm_gate[0]:
ifmarket_value < size_gate:
? ? ? ? ? ? ? ? label = [symbol, stock_return, context.BM_SMA, context.MV_SMA, market_value]
else:
? ? ? ? ? ? ? ? label = [symbol, stock_return, context.BM_SMA, context.MV_BIG, market_value]
elifpb < bm_gate[1]:
ifmarket_value < size_gate:
? ? ? ? ? ? ? ? label = [symbol, stock_return, context.BM_MID, context.MV_SMA, market_value]
else:
? ? ? ? ? ? ? ? label = [symbol, stock_return, context.BM_MID, context.MV_BIG, market_value]
elifmarket_value < size_gate:
? ? ? ? ? ? label = [symbol, stock_return, context.BM_BIG, context.MV_SMA, market_value]
else:
? ? ? ? ? ? label = [symbol, stock_return, context.BM_BIG, context.MV_BIG, market_value]
iflen(x_return) ==0:
? ? ? ? ? ? x_return = label
else:
? ? ? ? ? ? x_return = np.vstack([x_return, label])
stocks = DataFrame(data=x_return, columns=['symbol','return','BM','NEGOTIABLEMV','mv'])
? ? stocks.index = stocks.symbol
columns = ['return','BM','NEGOTIABLEMV','mv']
forcolumnincolumns:
? ? ? ? stocks[column] = stocks[column].astype(np.float64)
# 計算SMB.HML和市場收益率
# 獲取小市值組合的市值加權組合收益率
? ? smb_s = (market_value_weighted(stocks, context.MV_SMA, context.BM_SMA) +
? ? ? ? ? ? market_value_weighted(stocks, context.MV_SMA, context.BM_MID) +
market_value_weighted(stocks, context.MV_SMA, context.BM_BIG)) /3
# 獲取大市值組合的市值加權組合收益率
? ? smb_b = (market_value_weighted(stocks, context.MV_BIG, context.BM_SMA) +
? ? ? ? ? ? market_value_weighted(stocks, context.MV_BIG, context.BM_MID) +
market_value_weighted(stocks, context.MV_BIG, context.BM_BIG)) /3
? ? smb = smb_s - smb_b
# 獲取大賬面市值比組合的市值加權組合收益率
hml_b = (market_value_weighted(stocks, context.MV_SMA,3) +
market_value_weighted(stocks, context.MV_BIG, context.BM_BIG)) /2
# 獲取小賬面市值比組合的市值加權組合收益率
? ? hml_s = (market_value_weighted(stocks, context.MV_SMA, context.BM_SMA) +
market_value_weighted(stocks, context.MV_BIG, context.BM_SMA)) /2
? ? hml = hml_b - hml_s
close = history_n(symbol='SHSE.000300', frequency='1d', count=context.date +1,
end_time=last_day, fields='close', skip_suspended=True,
fill_missing='Last', adjust=ADJUST_PREV, df=True)['close'].values
market_return = close[-1] / close[0] -1
? ? coff_pool = []
# 對每只股票進行回歸獲取其alpha值
forstockinstocks.index:
x_value = np.array([[market_return], [smb], [hml], [1.0]])
y_value = np.array([stocks['return'][stock]])
# OLS估計系數
coff = np.linalg.lstsq(x_value.T, y_value)[0][3]
? ? ? ? coff_pool.append(coff)
# 獲取alpha最小并且小于0的10只的股票進行操作(若少于10只則全部買入)
stocks['alpha'] = coff_pool
stocks = stocks[stocks.alpha <0].sort_values(by='alpha').head(10)
? ? symbols_pool = stocks.index.tolist()
? ? positions = context.account().positions()
# 平不在標的池的股票
forpositioninpositions:
symbol = position['symbol']
ifsymbolnotinsymbols_pool:
order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print('市價單平不在標的池的', symbol)
# 獲取股票的權重
? ? percent = context.ratio / len(symbols_pool)
# 買在標的池中的股票
forsymbolinsymbols_pool:
? ? ? ? order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print(symbol,'以市價單調多倉到倉位', percent)
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='strategy_id',
filename='main.py',
? ? ? ? mode=MODE_BACKTEST,
token='token_id',
backtest_start_time='2017-07-01 08:00:00',
backtest_end_time='2017-10-01 16:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
try:
importtalib
except:
print('請安裝TA-Lib庫')
fromgm.apiimport*
'''
本策略首先買入SHSE.600000股票10000股
隨后根據60s的數據來計算MACD(12,26,9)線,并在MACD>0的時候買入100股,MACD<0的時候賣出100股
但每日操作的股票數不超過原有倉位,并于收盤前把倉位調整至開盤前的倉位
回測數據為:SHSE.600000的60s數據
回測時間為:2017-09-01 08:00:00到2017-10-01 16:00:00
'''
definit(context):
# 設置標的股票
context.symbol ='SHSE.600000'
# 用于判定第一個倉位是否成功開倉
context.first =0
# 訂閱浦發銀行, bar頻率為1min
subscribe(symbols=context.symbol, frequency='60s', count=35)
# 日內回轉每次交易100股
context.trade_n =100
# 獲取昨今天的時間
context.day = [0,0]
# 用于判斷是否觸發了回轉邏輯的計時
context.ending =0
defon_bar(context, bars):
bar = bars[0]
ifcontext.first ==0:
# 最開始配置倉位
# 需要保持的總倉位
context.total =10000
# 購買10000股浦發銀行股票
? ? ? ? order_volume(symbol=context.symbol, volume=context.total, side=PositionSide_Long,
? ? ? ? ? ? ? ? ? ? order_type=OrderType_Market, position_effect=PositionEffect_Open)
print(context.symbol,'以市價單開多倉10000股')
context.first =1.
day = bar.bob.strftime('%Y-%m-%d')
context.day[-1] = day[-2:]
# 每天的倉位操作
context.turnaround = [0,0]
return
# 更新最新的日期
day = bar.bob.strftime('%Y-%m-%d %H:%M:%S')
context.day[0] = bar.bob.day
# 若為新的一天,獲取可用于回轉的昨倉
ifcontext.day[0] != context.day[-1]:
context.ending =0
context.turnaround = [0,0]
ifcontext.ending ==1:
return
# 若有可用的昨倉則操作
ifcontext.total >=0:
# 獲取時間序列數據
symbol = bar['symbol']
recent_data = context.data(symbol=symbol, frequency='60s', count=35, fields='close')
# 計算MACD線
macd = talib.MACD(recent_data['close'].values)[0][-1]
# 根據MACD>0則開倉,小于0則平倉
ifmacd >0:
# 多空單向操作都不能超過昨倉位,否則最后無法調回原倉位
ifcontext.turnaround[0] + context.trade_n < context.total:
# 計算累計倉位
context.turnaround[0] += context.trade_n
? ? ? ? ? ? ? ? order_volume(symbol=context.symbol, volume=context.trade_n, side=PositionSide_Long,
? ? ? ? ? ? ? ? ? ? ? ? ? ? order_type=OrderType_Market, position_effect=PositionEffect_Open)
print(symbol,'市價單開多倉', context.trade_n,'股')
elifmacd <0:
ifcontext.turnaround[1] + context.trade_n < context.total:
context.turnaround[1] += context.trade_n
? ? ? ? ? ? ? ? order_volume(symbol=context.symbol, volume=context.trade_n, side=PositionSide_Short,
? ? ? ? ? ? ? ? ? ? ? ? ? ? order_type=OrderType_Market, position_effect=PositionEffect_Close)
print(symbol,'市價單平多倉', context.trade_n,'股')
# 臨近收盤時若倉位數不等于昨倉則回轉所有倉位
ifday[11:16] =='14:55'orday[11:16] =='14:57':
? ? ? ? ? ? position = context.account().position(symbol=context.symbol, side=PositionSide_Long)
ifposition['volume'] != context.total:
? ? ? ? ? ? ? ? order_target_volume(symbol=context.symbol, volume=context.total, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print('市價單回轉倉位操作...')
context.ending =1
# 更新過去的日期數據
context.day[-1] = context.day[0]
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='strategy_id',
filename='main.py',
? ? ? ? mode=MODE_BACKTEST,
token='token_id',
backtest_start_time='2017-09-01 08:00:00',
backtest_end_time='2017-10-01 16:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=2000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
importnumpyasnp
fromgm.apiimport*
frompandasimportDataFrame
'''
本策略以0.8為初始權重跟蹤指數標的滬深300中權重大于0.35%的成份股.
個股所占的百分比為(0.8*成份股權重)*100%.然后根據個股是否:
1.連續上漲5天 2.連續下跌5天
來判定個股是否為強勢股/弱勢股,并對其把權重由0.8調至1.0或0.6
回測時間為:2017-07-01 08:50:00到2017-10-01 17:00:00
'''
definit(context):
# 資產配置的初始權重,配比為0.6-0.8-1.0
context.ratio =0.8
# 獲取滬深300當時的成份股和相關數據
stock300 = get_history_constituents(index='SHSE.000300', start_date='2017-06-30', end_date='2017-06-30')[0][
'constituents']
? ? stock300_symbol = []
? ? stock300_weight = []
forkeyinstock300:
# 保留權重大于0.35%的成份股
if(stock300[key] /100) >0.0035:
? ? ? ? ? ? stock300_symbol.append(key)
stock300_weight.append(stock300[key] /100)
context.stock300 = DataFrame([stock300_weight], columns=stock300_symbol, index=['weight']).T
print('選擇的成分股權重總和為: ', np.sum(stock300_weight))
subscribe(symbols=stock300_symbol, frequency='1d', count=5, wait_group=True)
defon_bar(context, bars):
# 若沒有倉位則按照初始權重開倉
forbarinbars:
symbol = bar['symbol']
? ? ? ? position = context.account().position(symbol=symbol, side=PositionSide_Long)
ifnotposition:
buy_percent = context.stock300['weight'][symbol] * context.ratio
? ? ? ? ? ? order_target_percent(symbol=symbol, percent=buy_percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print(symbol,'以市價單開多倉至倉位:', buy_percent)
else:
# 獲取過去5天的價格數據,若連續上漲則為強勢股,權重+0.2;若連續下跌則為弱勢股,權重-0.2
recent_data = context.data(symbol=symbol, frequency='1d', count=5, fields='close')['close'].tolist()
ifall(np.diff(recent_data) >0):
buy_percent = context.stock300['weight'][symbol] * (context.ratio +0.2)
? ? ? ? ? ? ? ? order_target_percent(symbol=symbol, percent=buy_percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print('強勢股', symbol,'以市價單調多倉至倉位:', buy_percent)
elifall(np.diff(recent_data) <0):
buy_percent = context.stock300['weight'][symbol] * (context.ratio -0.2)
? ? ? ? ? ? ? ? order_target_percent(symbol=symbol, percent=buy_percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print('弱勢股', symbol,'以市價單調多倉至倉位:', buy_percent)
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='strategy_id',
filename='main.py',
? ? ? ? mode=MODE_BACKTEST,
token='token_id',
backtest_start_time='2017-07-01 08:50:00',
backtest_end_time='2017-10-01 17:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
importnumpyasnp
fromgm.apiimport*
'''
本策略每隔1個月定時觸發計算SHSE.000910.SHSE.000909.SHSE.000911.SHSE.000912.SHSE.000913.SHSE.000914
(300工業.300材料.300可選.300消費.300醫藥.300金融)這幾個行業指數過去
20個交易日的收益率并選取了收益率最高的指數的成份股獲取并獲取了他們的市值數據
隨后把倉位調整至市值最大的5只股票上
回測數據為:SHSE.000910.SHSE.000909.SHSE.000911.SHSE.000912.SHSE.000913.SHSE.000914和他們的成份股
回測時間為:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
definit(context):
# 每月第一個交易日的09:40 定時執行algo任務
schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
# 用于篩選的行業指數
context.index = ['SHSE.000910','SHSE.000909','SHSE.000911','SHSE.000912','SHSE.000913','SHSE.000914']
# 用于統計數據的天數
context.date =20
# 最大下單資金比例
context.ratio =0.8
defalgo(context):
# 獲取當天的日期
? ? today = context.now
# 獲取上一個交易日
last_day = get_previous_trading_date(exchange='SHSE', date=today)
? ? return_index = []
# 獲取并計算行業指數收益率
foriincontext.index:
return_index_his = history_n(symbol=i, frequency='1d', count=context.date, fields='close,bob',
fill_missing='Last', adjust=ADJUST_PREV, end_time=last_day, df=True)
return_index_his = return_index_his['close'].values
return_index.append(return_index_his[-1] / return_index_his[0] -1)
# 獲取指定數內收益率表現最好的行業
? ? sector = context.index[np.argmax(return_index)]
print('最佳行業指數是: ', sector)
# 獲取最佳行業指數成份股
symbols = get_history_constituents(index=sector, start_date=last_day, end_date=last_day)[0]['constituents'].keys()
# 獲取當天有交易的股票
? ? not_suspended_info = get_history_instruments(symbols=symbols, start_date=today, end_date=today)
not_suspended_symbols = [item['symbol']foriteminnot_suspended_infoifnotitem['is_suspended']]
# 獲取最佳行業指數成份股的市值,從大到小排序并選取市值最大的5只股票
fin = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended_symbols, start_date=last_day,
end_date=last_day, limit=5, fields='NEGOTIABLEMV', order_by='-NEGOTIABLEMV', df=True)
fin.index = fin['symbol']
# 計算權重
percent =1.0/ len(fin.index) * context.ratio
# 獲取當前所有倉位
? ? positions = context.account().positions()
# 如標的池有倉位,平不在標的池的倉位
forpositioninpositions:
symbol = position['symbol']
ifsymbolnotinfin.index:
order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print('市價單平不在標的池的', symbol)
# 對標的池進行操作
forsymbolinfin.index:
? ? ? ? order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print(symbol,'以市價單調整至倉位', percent)
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='strategy_id',
filename='main.py',
? ? ? ? mode=MODE_BACKTEST,
token='token_id',
backtest_start_time='2017-07-01 08:00:00',
backtest_end_time='2017-10-01 16:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
fromgm.apiimport*
'''
本策略通過獲取SHSE.000300滬深300的成份股數據并統計其30天內
開盤價大于前收盤價的天數,并在該天數大于閾值10的時候加入股票池
隨后對不在股票池的股票平倉并等權配置股票池的標的,每次交易間隔1個月.
回測數據為:SHSE.000300在2015-01-15的成份股
回測時間為:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
definit(context):
# 每月第一個交易日的09:40 定時執行algo任務
schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
# context.count_bench累計天數闕值
context.count_bench =10
# 用于對比的天數
context.count =30
# 最大交易資金比例
context.ratio =0.8
defalgo(context):
# 獲取當前時間
? ? now = context.now
# 獲取上一個交易日
last_day = get_previous_trading_date(exchange='SHSE', date=now)
# 獲取滬深300成份股
context.stock300 = get_history_constituents(index='SHSE.000300', start_date=last_day,
end_date=last_day)[0]['constituents'].keys()
# 獲取當天有交易的股票
? ? not_suspended_info = get_history_instruments(symbols=context.stock300, start_date=now, end_date=now)
not_suspended_symbols = [item['symbol']foriteminnot_suspended_infoifnotitem['is_suspended']]
? ? trade_symbols = []
ifnotnot_suspended_symbols:
print('沒有當日交易的待選股票')
return
forstockinnot_suspended_symbols:
recent_data = history_n(symbol=stock, frequency='1d', count=context.count, fields='pre_close,open',
fill_missing='Last', adjust=ADJUST_PREV, end_time=now, df=True)
diff = recent_data['open'] - recent_data['pre_close']
# 獲取累計天數超過闕值的標的池.并剔除當天沒有交易的股票
iflen(diff[diff >0]) >= context.count_bench:
? ? ? ? ? ? trade_symbols.append(stock)
print('本次股票池有股票數目: ', len(trade_symbols))
# 計算權重
percent =1.0/ len(trade_symbols) * context.ratio
# 獲取當前所有倉位
? ? positions = context.account().positions()
# 如標的池有倉位,平不在標的池的倉位
forpositioninpositions:
symbol = position['symbol']
ifsymbolnotintrade_symbols:
order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print('市價單平不在標的池的', symbol)
# 對標的池進行操作
forsymbolintrade_symbols:
? ? ? ? order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print(symbol,'以市價單調整至權重', percent)
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='strategy_id',
filename='main.py',
? ? ? ? mode=MODE_BACKTEST,
token='token_id',
backtest_start_time='2017-07-01 08:00:00',
backtest_end_time='2017-10-01 16:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
fromdatetimeimportdatetime
importnumpyasnp
fromgm.apiimport*
importsys
try:
fromsklearnimportsvm
except:
print('請安裝scikit-learn庫和帶mkl的numpy')
sys.exit(-1)
'''
本策略選取了七個特征變量組成了滑動窗口長度為15天的訓練集,隨后訓練了一個二分類(上漲/下跌)的支持向量機模型.
若沒有倉位則在每個星期一的時候輸入標的股票近15個交易日的特征變量進行預測,并在預測結果為上漲的時候購買標的.
若已經持有倉位則在盈利大于10%的時候止盈,在星期五損失大于2%的時候止損.
特征變量為:1.收盤價/均值2.現量/均量3.最高價/均價4.最低價/均價5.現量6.區間收益率7.區間標準差
訓練數據為:SHSE.600000浦發銀行,時間從2016-03-01到2017-06-30
回測時間為:2017-07-01 09:00:00到2017-10-01 09:00:00
'''
definit(context):
# 訂閱浦發銀行的分鐘bar行情
context.symbol ='SHSE.600000'
subscribe(symbols=context.symbol, frequency='60s')
start_date ='2016-03-01'# SVM訓練起始時間
end_date ='2017-06-30'# SVM訓練終止時間
# 用于記錄工作日
# 獲取目標股票的daily歷史行情
recent_data = history(context.symbol, frequency='1d', start_time=start_date, end_time=end_date, fill_missing='last',
df=True)
days_value = recent_data['bob'].values
days_close = recent_data['close'].values
? ? days = []
# 獲取行情日期列表
print('準備數據訓練SVM')
foriinrange(len(days_value)):
days.append(str(days_value[i])[0:10])
? ? x_all = []
? ? y_all = []
forindexinrange(15, (len(days) -5)):
# 計算三星期共15個交易日相關數據
start_day = days[index -15]
? ? ? ? end_day = days[index]
data = history(context.symbol, frequency='1d', start_time=start_day, end_time=end_day, fill_missing='last',
df=True)
close = data['close'].values
max_x = data['high'].values
min_n = data['low'].values
amount = data['amount'].values
? ? ? ? volume = []
foriinrange(len(close)):
? ? ? ? ? ? volume_temp = amount[i] / close[i]
? ? ? ? ? ? volume.append(volume_temp)
close_mean = close[-1] / np.mean(close)# 收盤價/均值
volume_mean = volume[-1] / np.mean(volume)# 現量/均量
max_mean = max_x[-1] / np.mean(max_x)# 最高價/均價
min_mean = min_n[-1] / np.mean(min_n)# 最低價/均價
vol = volume[-1]# 現量
return_now = close[-1] / close[0]# 區間收益率
std = np.std(np.array(close), axis=0)# 區間標準差
# 將計算出的指標添加到訓練集X
# features用于存放因子
? ? ? ? features = [close_mean, volume_mean, max_mean, min_mean, vol, return_now, std]
? ? ? ? x_all.append(features)
# 準備算法需要用到的數據
foriinrange(len(days_close) -20):
ifdays_close[i +20] > days_close[i +15]:
label =1
else:
label =0
? ? ? ? y_all.append(label)
x_train = x_all[:-1]
y_train = y_all[:-1]
# 訓練SVM
context.clf = svm.SVC(C=1.0, kernel='rbf', degree=3, gamma='auto', coef0=0.0, shrinking=True, probability=False,
tol=0.001, cache_size=200, verbose=False, max_iter=-1,
decision_function_shape='ovr', random_state=None)
? ? context.clf.fit(x_train, y_train)
print('訓練完成!')
defon_bar(context, bars):
bar = bars[0]
# 獲取當前年月日
today = bar.bob.strftime('%Y-%m-%d')
# 獲取數據并計算相應的因子
# 于星期一的09:31:00進行操作
# 當前bar的工作日
weekday = datetime.strptime(today,'%Y-%m-%d').isoweekday()
# 獲取模型相關的數據
# 獲取持倉
? ? position = context.account().position(symbol=context.symbol, side=PositionSide_Long)
# 如果bar是新的星期一且沒有倉位則開始預測
ifnotpositionandweekday ==1:
# 獲取預測用的歷史數據
data = history_n(symbol=context.symbol, frequency='1d', end_time=today, count=15,
fill_missing='last', df=True)
close = data['close'].values
train_max_x = data['high'].values
train_min_n = data['low'].values
train_amount = data['amount'].values
? ? ? ? volume = []
foriinrange(len(close)):
? ? ? ? ? ? volume_temp = train_amount[i] / close[i]
? ? ? ? ? ? volume.append(volume_temp)
close_mean = close[-1] / np.mean(close)
volume_mean = volume[-1] / np.mean(volume)
max_mean = train_max_x[-1] / np.mean(train_max_x)
min_mean = train_min_n[-1] / np.mean(train_min_n)
vol = volume[-1]
return_now = close[-1] / close[0]
std = np.std(np.array(close), axis=0)
# 得到本次輸入模型的因子
? ? ? ? features = [close_mean, volume_mean, max_mean, min_mean, vol, return_now, std]
features = np.array(features).reshape(1,-1)
prediction = context.clf.predict(features)[0]
# 若預測值為上漲則開倉
ifprediction ==1:
# 獲取昨收盤價
context.price = close[-1]
# 把浦發銀行的倉位調至95%
order_target_percent(symbol=context.symbol, percent=0.95, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print('SHSE.600000以市價單開多倉到倉位0.95')
# 當漲幅大于10%,平掉所有倉位止盈
elifpositionandbar.close / context.price >=1.10:
? ? ? ? order_close_all()
print('SHSE.600000以市價單全平多倉止盈')
# 當時間為周五并且跌幅大于2%時,平掉所有倉位止損
elifpositionandbar.close / context.price <1.02andweekday ==5:
? ? ? ? order_close_all()
print('SHSE.600000以市價單全平多倉止損')
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='strategy_id',
filename='main.py',
? ? ? ? mode=MODE_BACKTEST,
token='token_id',
backtest_start_time='2017-07-01 09:00:00',
backtest_end_time='2017-10-01 09:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
fromgm.apiimport*
importnumpyasnp
definit(context):
#獲得N日股票交易數據
context.N=5
#選擇一對股票
context.stock=['SZSE.000651','SZSE.000333']
# 每個交易日的09:40 定時執行algo任務
schedule(schedule_func=algo, date_rule='1d', time_rule='09:40:00')
defalgo(context):
# 獲取上一個交易日的日期
last_day = get_previous_trading_date(exchange='SHSE', date=context.now)
# 獲取當天有交易的股票,似乎無法同時獲得兩只股票的數據,所以只能麻煩一點
not_suspended = get_history_instruments(symbols=context.stock[0], start_date=last_day, end_date=last_day)
a = len([item['symbol']foriteminnot_suspendedifnotitem['is_suspended']])
not_suspended = get_history_instruments(symbols=context.stock[1], start_date=last_day,end_date=last_day)
b = len([item['symbol']foriteminnot_suspendedifnotitem['is_suspended']])
#如果有一支停牌,就跳過
ifa+b<2:
return
#獲得交易數據
prices1 = history_n(symbol=context.stock[0], frequency='1d', count=context.N, end_time=last_day, fields='close',
skip_suspended=True,
fill_missing=None, adjust=ADJUST_PREV, adjust_end_time='', df=True)
prices2=history_n(symbol=context.stock[1], frequency='1d', count=context.N, end_time=last_day, fields='close',
skip_suspended=True,
fill_missing=None, adjust=ADJUST_PREV, adjust_end_time='', df=True)
p1=list(prices1['close'])
p2=list(prices2['close'])
spread = np.array(p1[:-1]) - np.array(p2[:-1])
# 計算布林帶的上下軌
up = np.mean(spread) +2* np.std(spread)
down = np.mean(spread) -2* np.std(spread)
# 計算最新價差
spread_now = p1[-1] - p2[-1]
# 無交易時若價差上(下)穿布林帶上(下)軌則做空(多)價差
position_s1_long = context.account().position(symbol=context.stock[0], side=PositionSide_Long)
position_s2_long = context.account().position(symbol=context.stock[1], side=PositionSide_Long)
ifnotposition_s1_longandnotposition_s2_long:
ifspread_now > up:
order_target_percent(symbol=context.stock[1], percent=0.5, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
ifspread_now < down:
order_target_percent(symbol=context.stock[0], percent=0.5, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
# 價差回歸時平倉
elifposition_s2_long:
ifspread_now <= up:
? ? ? ? ? ? order_close_all()
elifposition_s1_long:
ifspread_now >= down:
? ? ? ? ? ? order_close_all()
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='73bb5bf2-a536-11e8-bd52-9cd21ef04ea9',
filename='配對交易.py',
? ? ? ? mode=MODE_BACKTEST,
token='c395247a76e8a5caeee699d668d6f550213bc418',
backtest_start_time='2014-01-01 08:00:00',
backtest_end_time='2018-08-01 16:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
fromgm.apiimport*
fromsklearnimportpreprocessing
'''
策略思路:
1、公司的資產負債率小于等于 25%
2、公司每股凈現金大于 0
3、當前股價與每股自由現金流量比小于 10(市現率)
4、在所有股票中取市盈率排倒數30%的股票(首先PE必須大于0)
5、PEG=市盈率/凈利潤增長率<0.5
回測數據:SHSE.000906的成份股
回測時間:2016-01-01 08:00:00到2018-01-01 16:00:00
'''
definit(context):
# 每月第一個交易日的09:40 定時執行algo任務
schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
defalgo(context):
# 獲取上一個交易日的日期
last_day = get_previous_trading_date(exchange='SHSE', date=context.now)
# 獲取滬深300成份股
stock800 = get_history_constituents(index='SHSE.000906', start_date=last_day,
end_date=last_day)[0]['constituents'].keys()
# 獲取當天有交易的股票
? ? not_suspended = get_history_instruments(symbols=stock800, start_date=last_day, end_date=last_day)
not_suspended = [item['symbol']foriteminnot_suspendedifnotitem['is_suspended']]
df = get_fundamentals(table='deriv_finance_indicator', symbols=not_suspended, start_date=last_day, end_date=last_day,
fields='ASSLIABRT,NCFPS,NPGRT', df=True)
fin=get_fundamentals(table='trading_derivative_indicator', symbols=not_suspended, start_date=last_day, end_date=last_day,
fields='PCLFY,PELFY', df=True)
df['PCLFY']=fin['PCLFY']
df['PELFY'] = fin['PELFY']
# 除去空值
? ? df = df.dropna()
df['PEG']=df['PELFY']/df['NPGRT']
? ? df.index=df.symbol
deldf['symbol'],df['pub_date'],df['end_date']
? ? print(df)
# 選出PEG小于0.5的部分
df = df[df['PEG'] <0.5]
# 選出債務總資產比小于0.25的部分
df = df[df["ASSLIABRT"] <25]
# 選出每股凈現金大于 0的部分
df = df[df["NCFPS"] >0]
# 選出市盈率大于零的部分
df = df[df['PELFY'] >0]
# 選出市現率小于10的部分
df = df[df['PCLFY'] <10]
? ? print(df)
# 剔除市盈率較高的股票(即剔除3分位數以后的股票)
iflen(df)<4:
? ? ? ? symbols_pool = list(df.index)
else:
df = df[(df['PELFY'] < df['PELFY'].quantile(0.3))]
? ? ? ? symbols_pool = list(df.index)
? ? print(symbols_pool)
? ? order_close_all()
? ? long=len(symbols_pool)
iflong==0:
return
# 獲取股票的權重
percent =1/ long
# 買在標的池中的股票
forsymbolinsymbols_pool:
? ? ? ? order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
#print(symbol, '以市價單調多倉到倉位', percent)
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='73bb5bf2-a536-11e8-bd52-9cd21ef04ea9',
filename='GARP.py',
? ? ? ? mode=MODE_BACKTEST,
token='c395247a76e8a5caeee699d668d6f550213bc418',
backtest_start_time='2016-01-01 08:00:00',
backtest_end_time='2018-01-01 16:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
# coding=utf-8
from__future__importprint_function, absolute_import, unicode_literals
fromgm.apiimport*
'''
本策略每隔1個月定時觸發計算SHSE.000300成份股的過去的EV/EBITDA并選取EV/EBITDA大于0的股票
隨后平掉排名EV/EBITDA不在最小的30的股票持倉并等權購買EV/EBITDA最小排名在前30的股票
并用相應的CFFEX.IF對應的真實合約等額對沖
回測數據為:SHSE.000300和他們的成份股和CFFEX.IF對應的真實合約
回測時間為:2017-07-01 08:00:00到2017-10-01 16:00:00
'''
definit(context):
# 每月第一個交易日09:40:00的定時執行algo任務
schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
# 設置開倉在股票和期貨的資金百分比(期貨在后面自動進行杠桿相關的調整)
context.percentage_stock =0.4
context.percentage_futures =0.4
defalgo(context):
# 獲取當前時刻
? ? now = context.now
# 獲取上一個交易日
last_day = get_previous_trading_date(exchange='SHSE', date=now)
# 獲取滬深300成份股
stock300 = get_history_constituents(index='SHSE.000300', start_date=last_day,
end_date=last_day)[0]['constituents'].keys()
# 獲取上一個工作日的CFFEX.IF對應的合約
index_futures = get_continuous_contracts(csymbol='CFFEX.IF', start_date=last_day, end_date=last_day)[-1]['symbol']
# 獲取當天有交易的股票
? ? not_suspended_info = get_history_instruments(symbols=stock300, start_date=now, end_date=now)
not_suspended_symbols = [item['symbol']foriteminnot_suspended_infoifnotitem['is_suspended']]
# 獲取成份股EV/EBITDA大于0并為最小的30個
fin = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended_symbols,
start_date=now, end_date=now, fields='EVEBITDA',
filter='EVEBITDA>0', order_by='EVEBITDA', limit=30, df=True)
? ? fin.index = fin.symbol
# 獲取當前倉位
? ? positions = context.account().positions()
# 平不在標的池或不為當前股指期貨主力合約對應真實合約的標的
forpositioninpositions:
symbol = position['symbol']
sec_type = get_instrumentinfos(symbols=symbol)[0]['sec_type']
# 若類型為期貨且不在標的池則平倉
ifsec_type == SEC_TYPE_FUTUREandsymbol != index_futures:
order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Short)
print('市價單平不在標的池的', symbol)
elifsymbolnotinfin.index:
order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print('市價單平不在標的池的', symbol)
# 獲取股票的權重
? ? percent = context.percentage_stock / len(fin.index)
# 買在標的池中的股票
forsymbolinfin.index:
? ? ? ? order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Long)
print(symbol,'以市價單調多倉到倉位', percent)
# 獲取股指期貨的保證金比率
ratio = get_history_instruments(symbols=index_futures, start_date=last_day, end_date=last_day)[0]['margin_ratio']
# 更新股指期貨的權重
? ? percent = context.percentage_futures * ratio
# 買入股指期貨對沖
? ? order_target_percent(symbol=index_futures, percent=percent, order_type=OrderType_Market,
? ? ? ? ? ? ? ? ? ? ? ? position_side=PositionSide_Short)
print(index_futures,'以市價單調空倉到倉位', percent)
if__name__ =='__main__':
'''
? ? strategy_id策略ID,由系統生成
? ? filename文件名,請與本文件名保持一致
? ? mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
? ? token綁定計算機的ID,可在系統設置-密鑰管理中生成
? ? backtest_start_time回測開始時間
? ? backtest_end_time回測結束時間
? ? backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
? ? backtest_initial_cash回測初始資金
? ? backtest_commission_ratio回測傭金比例
? ? backtest_slippage_ratio回測滑點比例
? ? '''
run(strategy_id='strategy_id',
filename='main.py',
? ? ? ? mode=MODE_BACKTEST,
token='token_id',
backtest_start_time='2017-07-01 08:00:00',
backtest_end_time='2017-10-01 16:00:00',
? ? ? ? backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
鏈接下文:經典的股票/期貨量化交易策略,拿來即用的Python策略源碼(2)