一個(gè)適用于新手的量化交易模板

ricequant 的用戶 ming gao 在社區(qū)里為我們貢獻(xiàn)了一個(gè)很有趣的模板~
小編決定把回測結(jié)果放在前面

以下是正文:
關(guān)鍵詞:策略模板蒋腮、策略、策略交易、新人千绪、模板、模塊……
引言:
在rice里混了大半年了梗脾,學(xué)習(xí)了不少大牛的有用知識(shí)荸型,也編寫了一大堆的有的沒的策略,但是每次都面臨大量的重復(fù)勞動(dòng)炸茧,費(fèi)時(shí)費(fèi)力瑞妇,于是這里就總結(jié)了一個(gè)適合新人的交易策略的模板分享給大家。
原理:
看了大家的策略梭冠,和查閱了一些資料辕狰,也總結(jié)了和歸納了一些,大概分為控漠,選股柳琢、進(jìn)場時(shí)機(jī)、持倉平衡润脸、現(xiàn)金管理柬脸、出場時(shí)機(jī)、風(fēng)險(xiǎn)管理毙驯,一些工具組件~
不廢話了倒堕,直接上demo代碼簡單寫~
模板代碼:
說明:分鐘回測,組合初始100萬現(xiàn)金爆价,交易手續(xù)默認(rèn)的垦巴,無賣空,benchmark為默認(rèn)铭段,進(jìn)場策略輸出了股票列表骤宣,出場策略也是返回要賣出的股票列表……
1、傳奇的小市值策略(市值最小的100只股票做為每天的備選列表)序愚,這個(gè)因子表現(xiàn)的最好憔披,為避免模板的demo曲線表現(xiàn)太差,所以用了這個(gè)吸引眼球的選股因子爸吮,高手勿噴芬膝,勿笑;
2形娇、進(jìn)場以大家熟悉的5日均線上傳10日均線锰霜,并保持20日線為進(jìn)場條件;(感覺自己寫復(fù)雜了桐早,反正是模板)
3癣缅、出場為低于20日線的99%為強(qiáng)制出場(20日線厨剪,在近兩年基本作為了行業(yè)標(biāo)配了,反正有點(diǎn)用)
4友存、持倉策略:在市值不便的情況下平均持倉祷膳,每日臨近收盤進(jìn)行再平衡,理想情況保持每只持倉占比相等(
5爬立、現(xiàn)金管理:本來想再收盤前現(xiàn)金買進(jìn)“銀華日利”钾唬,但由于默認(rèn)市價(jià)交易滑點(diǎn)太大万哪,就省略了(要限價(jià)交易才可能有利潤侠驯,但是這里也發(fā)現(xiàn)尾盤表現(xiàn)非常不好,就注釋掉了)
6奕巍、風(fēng)險(xiǎn)管理:略了吟策,流傳一個(gè)大盤跌過3%的強(qiáng)制止損風(fēng)險(xiǎn)策略,小市值也可以增加二八輪動(dòng)的擇時(shí)的止,沒有加上檩坚,有興趣可以自己弄著玩,加這個(gè)模塊里诅福;
7匾委、交易方式:為了避免過大的成家量超過25%的error,這里都下的限價(jià)單氓润,但是后續(xù)模塊化吧赂乐,另控制了單只持倉不超過10%~(模塊寫起來比較復(fù)雜,還要新建dict進(jìn)行撤單再下單等計(jì)算咖气,后續(xù)成熟了挨措,再拿出來分享)
8、工具:
trans崩溪、歷史數(shù)據(jù)強(qiáng)制轉(zhuǎn)化成真正的DataFrame(效率問題浅役,做了.T的來回變換),問licco說伶唯,其實(shí)2016年5月2X后就不需要了
n日內(nèi)隨機(jī)交易的收益率概率(例子中未用到)
多個(gè)list里取交集觉既,懶得每次都寫了,干脆寫了個(gè)小函數(shù)
標(biāo)的上市自然日的函數(shù)乳幸,避免次新股對收益干擾太大奋救,要真像炒次新股,要好好研究一下反惕,個(gè)人做過嘗試發(fā)現(xiàn)尝艘,高風(fēng)險(xiǎn)高利潤,大盤擇時(shí)比較關(guān)鍵姿染,干脆這里做了過濾比如一定要上市超過60個(gè)自然日
是否漲跌停區(qū)間背亥,一定要可交易秒际,人家都封版了,交易量有狡汉,關(guān)咱策略毛事娄徊,所以也進(jìn)行了過濾
因?yàn)榉昼娀販y,所以選擇了14:50作為買入時(shí)間點(diǎn)盾戴,而出場選擇每15分鐘采樣計(jì)算一次(性能壓力和必要性的問題)寄锐,14:59(后來發(fā)現(xiàn)深圳市場應(yīng)該14點(diǎn)56,要不57開始深圳會(huì)集合競價(jià)了尖啡,但是例子里沒有調(diào)整橄仆,所以還是error一大堆,見笑了)
接下來就是代碼啦衅斩,可讀性還是很強(qiáng)的盆顾,大家可以去ricequant上克隆一下運(yùn)行起來試試。

import pandas as pd
import numpy as np
import time
import math
import itertools

# 數(shù)據(jù)準(zhǔn)備

def init_variables (context):
    context.init = 0 
    context.days = 0
    context.barcount = 0
    context.choosenum = 300
    context.obv = 50
    context.tj1 = 5 # 5日均線
    context.tj2 = 10 # 10日均線
    context.tj3 = 20 # 20日均線
    context.his = pd.DataFrame()
    return


'''第1部畏梆、選擇標(biāo)的'''

def choose_target(context):
    # 最小市值的100只標(biāo)的
    df = get_fundamentals(
        query(fundamentals.eod_derivative_indicator.market_cap)
        .order_by(fundamentals.eod_derivative_indicator.market_cap.asc())
        .limit(context.choosenum)
    )
    context.stocks = [stock for stock in df][:100]
    return context.stocks

'''第2部您宪、入場策略'''
#2.1 大盤環(huán)境問題
    #可增加外部數(shù)據(jù)

#2.2 個(gè)股選擇問題,最后還要過濾非跌停奠涌、上市天數(shù)宪巨、非停牌的標(biāo)的(st未過濾)
def for_buy(context, bar_dict, his):
    #2.2.1 備選中標(biāo)的站上5日線
    def tj1(context, bar_dict, his):
        ma_n = pd.rolling_mean(his, context.tj1)
        temp = his - ma_n
        temp_s = list(temp[temp>0].iloc[-1,:].dropna().index)
        return temp_s
    #2.2.2 備選中標(biāo)的站上10日線
    def tj2(context, bar_dict, his):
        ma_n = pd.rolling_mean(his, context.tj2)
        temp = his - ma_n
        temp_s = list(temp[temp>0].iloc[-1,:].dropna().index)
        return temp_s
    
    #2.2.2 所謂金叉,今天短均線大于長均線溜畅,上一個(gè)bar反之
    def tj3(context, bar_dict, his):
        mas = pd.rolling_mean(his, context.tj1)
        mal = pd.rolling_mean(his, context.tj2)
        temp = mas - mal
        temp_jc = list(temp[temp>0].iloc[-1,:].dropna().index)
        temp_r = list(temp[temp>0].iloc[-2,:].dropna().index)
        temp = []
        for stock in temp_jc:
            if stock not in temp_r:
                temp.append(stock)
        return temp
    
    #整合各個(gè)子條件的交集
    
    l1 = tj1(context, bar_dict, his)
    l2 = tj2(context, bar_dict, his)
    l3 = tj3(context, bar_dict, his)
    l_tar = jj_list([l1,l2,l3])
    to_buy = []
    #過濾上市時(shí)間捏卓、是否漲停、是否停牌等條件
    if l_tar:
        for stock in l_tar:
            con1 = ipo_days(stock,context.now)>60
            con2 = zdt_trade(stock,context,bar_dict)
            con3 = bar_dict[stock].is_trading
            if con1 & con2 & con3:
                to_buy.append(stock)
    return to_buy


'''第3部达皿、持倉組合的微調(diào)策略'''
# 平均市值做微調(diào)
def for_balance(context, bar_dict):
    #mvalues = context.portfolio.market_value
    #avalues = context.portfolio.portfolio_value
    #per = mvalues / avalues
    hlist = []
    for stock in context.portfolio.positions:
        hlist.append([stock,bar_dict[stock].last * context.portfolio.positions[stock].quantity])
    
    if hlist:
        hlist = sorted(hlist,key=lambda x:x[1], reverse=True)
        temp = 0
        for li in hlist:
            temp += li[1]
        for li in hlist:
            if bar_dict[li[0]].is_trading:
                order_target_value(li[0], temp/len(hlist))
    return

'''第4部天吓、出場策略'''
# 小于20日均線,并且可交易峦椰,沒跌停
def for_sell(context, bar_dict):
    to_sell = []
    for stock in context.portfolio.positions:
        con1 = bar_dict[stock].last < 0.99 * bar_dict[stock].mavg(20, frequency='day')
        con2 = bar_dict[stock].is_trading
        con3 = zdt_trade(stock,context,bar_dict)
        if con1 & con2 & con3:
            to_sell.append(stock)
    return to_sell

'''第5部龄寞、閑置資金效率最大化'''
def for_cash(context, bar_dict):
    cash = context.portfolio.cash
    #order_target_value('511880.XSHG',cash) 注釋掉因?yàn)榛c(diǎn)太大,可以買一個(gè)貨基汤功,或者逆回購
    return 

'''第6部物邑、風(fēng)險(xiǎn)控制'''
def alert_rish(context,bar_dict):
    #這里如果給出策略,要強(qiáng)制執(zhí)行滔金,注意在handle優(yōu)先級(jí)高于所有
    pass

'''第7部色解、備用組件'''

#7.1 將his的非標(biāo)DF進(jìn)行轉(zhuǎn)換,licco說現(xiàn)在不用轉(zhuǎn)換了餐茵,我還是保留了:)
def trans(df):
    temp = pd.DataFrame()
    for col in df.index:
        temp[col] = df.T[col]
    return temp.T

#7.2 計(jì)算n日概率隨機(jī)交易的概率收益率
def rts_sj(df,n,m): 
    dfp_pct = df.pct_change()
    def the_list(df,n,m):
        temp = []
        for i in range(n,n+m):
            temp.append(df.iloc[-i,:] + 1)
        return temp
    def from_list(self,num):
        result = []
        for i in range(1,num+1):
            result.extend(list(itertools.combinations(self,i)))
        return result
    def rts_n(tu):
        sum0 = []
        for i in tu:
            temp = 1
            for z in i:
                temp = temp * z
            temp = temp**(1/len(i))
            sum0.append(temp)
        sum1 = 0
        for i in sum0:
            sum1 = sum1 + i - 1
        return sum1/len(sum0)
    return rts_n(from_list(the_list(dfp_pct,n,m),m)) 

#7.3 多l(xiāng)ist獲得并集
def jj_list(tar_list):
    temp = tar_list[0]
    for i in tar_list:
        temp = list(set(temp).intersection(set(i)))
    return temp

#7.4 標(biāo)的上市時(shí)間距離參照時(shí)間的自然日數(shù)量
def ipo_days(stock, today):
    ssrq = instruments(stock).listed_date.replace(tzinfo=None)
    today = today.replace(tzinfo=None)
    return (today - ssrq).days

#7.5 判斷當(dāng)前標(biāo)在可交易區(qū)間內(nèi)(非漲跌停)
def zdt_trade(stock, context, bar_dict):
    yesterday = history(2,'1d', 'close')[stock].values[-1]
    zt = round(1.10 * yesterday,2)
    dt = round(0.99 * yesterday,2)
    return dt < bar_dict[stock].last < zt
    



'''--------------華麗的分割線----------------'''

def init(context):
    init_variables(context)
    choose_target(context)


# before_trading此函數(shù)會(huì)在每天交易開始前被調(diào)用科阎,當(dāng)天只會(huì)被調(diào)用一次
def before_trading(context, bar_dict):
    choose_target(context)
    update_universe(context.stocks)
    context.his = trans(history(context.obv,'1d','close'))
    context.barcount = 0
    context.init = 1
    pass


# 你選擇的證券的數(shù)據(jù)更新將會(huì)觸發(fā)此段邏輯,例如日或分鐘歷史數(shù)據(jù)切片或者是實(shí)時(shí)數(shù)據(jù)切片更新
def handle_bar(context, bar_dict):
    context.barcount += 1
    
    alert_rish(context,bar_dict)
    
    #模擬交易第一次開始忿族,如果是交易時(shí)間可能運(yùn)行不了before_trading,所以這里做了個(gè)參數(shù)來控制這種出錯(cuò)的特例
    if context.init == 0:
        update_universe(context.stocks)
        context.his = trans(history(context.obv, '1d', 'close'))
        context.barcount = 0
        context.init = 1
    else:
        pass
    
    if context.barcount % 15 == 0:
        to_sell = for_sell(context, bar_dict)
        if to_sell:
            for oid in get_open_orders().keys():
                cancel_order(oid)
            for stock in to_sell:
                order_target_value(stock, 0, style=LimitOrder(bar_dict[stock].last*0.995))
    
    if context.barcount == 230:
        his = trans(history(2,'1m','close'))
        his = context.his.append(his.iloc[-1,:],ignore_index=True)
        to_buy = for_buy(context, bar_dict, his)
        if to_buy:
            print (to_buy)
        hnum = len(list(set(to_buy).union(set(context.portfolio.positions.keys()))))
        for stock in to_buy:
            if hnum <10:
                print ('buy', stock, bar_dict[stock].high * 1.005)
                order_target_percent(stock, 0.99/10, style=LimitOrder(bar_dict[stock].high * 1.005))
            else:
                order_target_percent(stock, 0.99um, style=LimitOrder(bar_dict[stock].high * 1.005))
    
    if context.barcount == 236: 
        his = trans(history(2,'1m','close'))
        his = context.his.append(his.iloc[-1,:],ignore_index=True)
        for_balance(context, bar_dict)
        for_cash(context, bar_dict)  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锣笨,一起剝皮案震驚了整個(gè)濱河市蝌矛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌错英,老刑警劉巖入撒,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異椭岩,居然都是意外死亡茅逮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門判哥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來献雅,“玉大人,你說我怎么就攤上這事姨伟〕土穑” “怎么了豆励?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵夺荒,是天一觀的道長。 經(jīng)常有香客問我良蒸,道長技扼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任据悔,我火速辦了婚禮猜欺,結(jié)果婚禮上拾弃,老公的妹妹穿的比我還像新娘。我一直安慰自己丽旅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布纺棺。 她就那樣靜靜地躺著榄笙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祷蝌。 梳的紋絲不亂的頭發(fā)上茅撞,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音巨朦,去河邊找鬼米丘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛糊啡,可吹牛的內(nèi)容都是我干的拄查。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼棚蓄,長吁一口氣:“原來是場噩夢啊……” “哼堕扶!你這毒婦竟也來了腺毫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤挣柬,失蹤者是張志新(化名)和其女友劉穎潮酒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邪蛔,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡急黎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了侧到。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勃教。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖匠抗,靈堂內(nèi)的尸體忽然破棺而出故源,到底是詐尸還是另有隱情,我是刑警寧澤汞贸,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布绳军,位于F島的核電站,受9級(jí)特大地震影響矢腻,放射性物質(zhì)發(fā)生泄漏门驾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一多柑、第九天 我趴在偏房一處隱蔽的房頂上張望奶是。 院中可真熱鬧,春花似錦竣灌、人聲如沸聂沙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽及汉。三九已至,卻和暖如春削樊,著一層夾襖步出監(jiān)牢的瞬間豁生,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國打工漫贞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留甸箱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓迅脐,卻偏偏與公主長得像芍殖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子谴蔑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 美豹金融的美股大學(xué)--https://www.usmeibao.com/knowledge.html 一豌骏、基礎(chǔ)篇 ...
    格式化_001閱讀 2,546評(píng)論 1 5
  • 1995年龟梦,美國影星布拉德 皮特曾經(jīng)主演過一部膾炙人口的懸疑偵探片《七宗罪》,想必大家一定都有看過窃躲。故事的最終:皮...
    睡眠科學(xué)化閱讀 1,183評(píng)論 0 10
  • 前言 文章介紹了股指期貨的基礎(chǔ)知識(shí)计贰,引用官方細(xì)則包括滬深300指數(shù)期貨,上證50股指期貨蒂窒,中證500股指期貨躁倒,5年...
    王奧OX閱讀 1,338評(píng)論 0 11
  • 幾回月亮西墜,幾回太陽升起 轉(zhuǎn)眼洒琢,就到了七夕 銀河的兩端秧秉,你溫情脈脈,我柔情萬千 多少回衰抑,月缺與月圓象迎,我望穿秋水 ...
    暖意人生1閱讀 296評(píng)論 0 2
  • 作為一名心理咨詢師砾淌,我的主要方向是情感咨詢,包括戀愛恋技,婚姻拇舀,親密關(guān)系及親子關(guān)系的咨詢等等逻族。最近遇到的一些來訪者蜻底,無...
    Andy尐雪閱讀 205評(píng)論 0 0