量化投資(ETF輪動(dòng))

雪球上看到一個(gè)大V的ETF輪動(dòng)策略,回測(cè)效果還不錯(cuò)骂维,比較適合個(gè)人投資者使用蚌父。

【策略思想】
針對(duì)多只指數(shù)基金哮兰,以等權(quán)重方式持有符合買入條件的基金,最高同時(shí)持有3只基金苟弛。沒(méi)有基金符合要求時(shí)空倉(cāng)
【策略理論依據(jù)】
輪動(dòng)策略的理論基礎(chǔ)是動(dòng)量效應(yīng)喝滞,也就是處于上漲狀態(tài)的基金會(huì)在一定時(shí)間內(nèi)保持上漲趨勢(shì)。
【買入條件】(兩個(gè)條件全部滿足才買入)
1嗡午、近13個(gè)交易日漲幅排名前三(設(shè)置漲幅閾值為0.1%)囤躁,選擇最強(qiáng)勢(shì)的基金;
2、當(dāng)前價(jià)大于13日均線狸演,主要用于過(guò)濾假突破信號(hào)言蛇。
【賣出條件】(三個(gè)條件滿足一個(gè)就賣出)
1、近13個(gè)交易日漲幅排名未入前三(先剔除不符合買入條件的基金再排序)宵距;
2腊尚、近13個(gè)交易日漲幅不足0.1%;
3满哪、當(dāng)前價(jià)小于近13個(gè)交易日均線
4婿斥、上證指數(shù)連續(xù)6日不過(guò)7日量線,無(wú)條件賣出哨鸭,提前出場(chǎng)等待

基于動(dòng)量的輪動(dòng)是一種偏進(jìn)攻型的策略民宿,不追求高勝率,核心邏輯在于“多賺少虧”像鸡,整體盈利活鹰。

輪動(dòng)策略的“少虧”是通過(guò)輪動(dòng)換倉(cāng)實(shí)現(xiàn)的,但是我們發(fā)現(xiàn)基礎(chǔ)策略的回撤幅度仍然是非常大的(超過(guò)35%)只估,通過(guò)同時(shí)持有多個(gè)標(biāo)的分散風(fēng)險(xiǎn)志群,我們把回撤控制在了25%以內(nèi)。

這個(gè)策略如果改了運(yùn)行時(shí)間的話蛔钙,回測(cè)結(jié)果差異非常大锌云,把交易時(shí)間設(shè)置在下午14:30以后會(huì)比較好。難道是因?yàn)槲覀兊氖袌?chǎng)在收盤前半個(gè)小時(shí)經(jīng)常出現(xiàn)逆趨勢(shì)的波動(dòng)吁脱?例如處于上漲周期的桑涎,經(jīng)常尾盤跳水,處于下降周期的豫喧,又經(jīng)常尾盤拉高石洗,這樣一買一賣,差價(jià)就出來(lái)了紧显。這應(yīng)該有一個(gè)統(tǒng)計(jì)學(xué)上的解釋讲衫。但如果真是如此,這就是一個(gè)值得注意的策略鈍化的潛在風(fēng)險(xiǎn)孵班,沒(méi)有辦法保證我們的市場(chǎng)風(fēng)格會(huì)一直如此涉兽。

不同時(shí)間段的回測(cè)收益曲線如下:

image.png
image.png
image.png

ETF輪動(dòng)
'''信號(hào)判斷:價(jià)格不低于13日均線,且價(jià)格相對(duì)于13日前上漲篙程,綜合評(píng)分排名第一或者低于第一不超過(guò)閾值
止損信號(hào):收益率峰值下跌20%點(diǎn)位枷畏,賣出全部,冷卻3天
確認(rèn)信號(hào):11:30
交易時(shí)間:14:40
均線周期:13
標(biāo)題:滬深寬基ETF輪動(dòng)策略低回撤
'''

from jqdata import *

=================================================
總體回測(cè)前設(shè)置參數(shù)和回測(cè)
=================================================

def initialize(context):
set_params()    #1設(shè)置策參數(shù)
set_variables() #2設(shè)置中間變量
set_backtest()  #3設(shè)置回測(cè)條件
set_slippage(FixedSlippage(0))
set_order_cost(OrderCost(open_tax=0, close_tax=0, \
    open_commission=0.0005, close_commission=0.0005,\
    close_today_commission=0, min_commission=5), type='fund')
run_daily(ETFtrade1, time='11:30')
run_daily(ETFtrade2, time='14:40')

1 設(shè)置參數(shù)

def set_params():
# 設(shè)置基準(zhǔn)收益
set_benchmark('000300.XSHG')
g.returnsRate = 0  #峰值收益率初始化
g.CoolingOff = 0  #冷卻期
g.signal = 'KEEP'  #交易信號(hào)初始化
g.lag = 13  #均線周期
g.shift = 0.2  #設(shè)置漲幅%偏差過(guò)濾閾值
g.last = '0' #持倉(cāng)股票代碼初始化
g.ETFList = np.array([
    ['399006.XSHE','159915.XSHE'], #創(chuàng)業(yè)板
    ['000300.XSHG','510300.XSHG'], #滬深300
    ['000905.XSHG','510500.XSHG'], #中證500
    #['399330.XSHE','159901.XSHE'], #深證100
    ['510880.XSHG','510880.XSHG'], #紅利ETF
    #['511010.XSHG','511010.XSHG'], #國(guó)債ETF
    #['518880.XSHG','518880.XSHG'], #黃金ETF
    ['399932.XSHE','159928.XSHE'] #消費(fèi)ETF
])

2 設(shè)置中間變量

def set_variables():
return

3 設(shè)置回測(cè)條件

def set_backtest():
set_option('use_real_price', True) #用真實(shí)價(jià)格交易
log.set_level('order', 'error')

=================================================
每日交易時(shí)
=================================================

def ETFtrade1(context):
g.signal = get_signal(context)

def ETFtrade2(context):
for stock in context.portfolio.positions.keys():
    if stock not in g.last:
        log.info("正在賣出遺留基金 %s" % stock)
        order_target_value(stock, 0)
if g.signal == 'sell_the_stocks':
    sell_the_stocks(context)
elif g.signal == 'KEEP':
    log.info("交易信號(hào):持倉(cāng)不變")
else:
    sell_the_stocks(context)    
    buy_the_stocks(context,g.signal)

5 獲取信號(hào)

def get_signal(context):
if KeepReturns(context): # 達(dá)到止損條件后發(fā)出空倉(cāng)信號(hào)
    if g.last == '0':# 持倉(cāng)為空
        log.info("交易信號(hào):冷卻期保持空倉(cāng)狀態(tài)")
        return 'KEEP'# 持倉(cāng)保持不變
    else:# 持倉(cāng)不為空
        log.info("交易信號(hào):收益率下跌超20%虱饿,空倉(cāng)止損")
        g.last = '0'
        return 'sell_the_stocks'

i=0 # 計(jì)數(shù)器初始化
# dapan_stoploss() # 調(diào)用大盤止損函數(shù)設(shè)置均線周期
# 創(chuàng)建保持計(jì)算結(jié)果的DataFrame
df = pd.DataFrame()
for row in g.ETFList:
    security = row[1]
# 獲取股票的收盤價(jià)
    close_data = attribute_history(security, g.lag, '1d', ['close'],df=False)
# 獲取股票現(xiàn)價(jià)
    current_data = get_current_data()
    current_price = current_data[security].last_price
# 獲取股票的階段收盤價(jià)漲幅
    cp_increase = (current_price/close_data['close'][0]-1)*100
# 取得過(guò)去 g.lag 天的平均價(jià)格
    ma_n1 = close_data['close'].mean()
# 計(jì)算前一收盤價(jià)與均值差值    
    pre_price = (current_price/ma_n1-1)*100
    df.loc[i,'股票代碼'] = row[1] # 把標(biāo)的股票代碼添加到DataFrame
    df.loc[i,'股票名稱'] = get_security_info(row[1]).display_name # 把標(biāo)的股票名稱添加到DataFrame
    df.loc[i,'周期漲幅%'] = cp_increase # 把計(jì)算結(jié)果添加到DataFrame
    df.loc[i,'均線差值%'] = pre_price # 把計(jì)算結(jié)果添加到DataFrame
    i=i+1

# 刪除不符合要求的標(biāo)的
for t in df.index:
    if df.loc[t,'周期漲幅%'] < 0 or df.loc[t,'均線差值%'] < 0:
    #if df.loc[t,'均線差值'] < 0:    
        df=df.drop(t)


# 對(duì)計(jì)算結(jié)果表格進(jìn)行從大到小排序
df.sort_values(by='周期漲幅%',ascending=False,inplace=True) # 按照漲幅排序
df.reset_index(drop=True, inplace=True) # 重新設(shè)置索引
df['周期漲幅%'].apply(lambda x:'%.2f' %x)
df['均線差值%'].apply(lambda x:'%.2f' %x)
log.info("行情統(tǒng)計(jì)結(jié)果表:\n%s" % (df))

if df.empty: # 表為空
    if g.last == '0':# 持倉(cāng)為空
        log.info("交易信號(hào):繼續(xù)保持空倉(cāng)狀態(tài)")
        return 'KEEP'# 持倉(cāng)保持不變
    else:# 持倉(cāng)不為空
        log.info("交易信號(hào):空倉(cāng)")
        g.last = '0'
        return 'sell_the_stocks' # 當(dāng)前價(jià)格低于均線賣出股票

elif g.last == '0': # 表不為空,持倉(cāng)為空,購(gòu)買排名第一股
    stockcode = str(df.iloc[0,0])
    g.last = stockcode
    log.info("交易信號(hào):買入 %s" % (stockcode))
    return stockcode
    
elif g.last != '0': # 表不為空 持倉(cāng)不為空
    if g.last not in df['股票代碼'].values: # 如果持倉(cāng)股不在表中,購(gòu)買排名第一股
        stockcode = str(df.iloc[0,0])
        g.last = stockcode
        log.info("交易信號(hào):買入 %s" % (stockcode))
        return stockcode
    if g.last in df['股票代碼'].values:# 如果持倉(cāng)股在表中
        for t in df.index: # 取得持倉(cāng)股漲幅
            if df.loc[t,'股票代碼'] == g.last:
                temp = df.loc[t,'周期漲幅%']
        if df.iloc[0,2] - temp < g.shift:  # 排名第一股漲幅差距低于閾值,返回繼續(xù)持倉(cāng)
            return 'KEEP' # 持倉(cāng)保持不變
        else: # 排名第一股漲幅差距大于閾值,換股
            stockcode = str(df.iloc[0,0])
            g.last = stockcode
            log.info("交易信號(hào):買入 %s" % (stockcode))
            return stockcode

賣出股票

def sell_the_stocks(context):
for stock in context.portfolio.positions.keys():
    return (log.info("正在賣出 %s" % stock), order_target_value(stock, 0))

買入股票

def buy_the_stocks(context,signal):
return (log.info("正在買入 %s"% signal 
),order_value(signal,context.portfolio.cash))

收益止損函數(shù)

def KeepReturns(context):
if g.CoolingOff > 0:
    g.CoolingOff = g.CoolingOff - 1
    return True
else:
    current_returns = context.portfolio.returns
    if current_returns > g.returnsRate:
        g.returnsRate = current_returns
        log.info("最高收益更新:{:.2%}".format(current_returns))
        return False
    elif current_returns - g.returnsRate > -0.2:
        return False
    else:
        current_returns - g.returnsRate-1 <= -0.2
        g.returnsRate = current_returns
        log.info("最高收益更新:{:.2%}".format(current_returns))
        g.CoolingOff = 3
        return True

=================================================
每日收盤后
=================================================

def after_trading_end(context):
log.info('今日持倉(cāng)情況:%s',context.portfolio.positions.keys())
print("總權(quán)益:{:.2f}萬(wàn)".format(context.portfolio.total_value/10000))
return
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拥诡,一起剝皮案震驚了整個(gè)濱河市触趴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渴肉,老刑警劉巖冗懦,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異仇祭,居然都是意外死亡披蕉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門乌奇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)没讲,“玉大人,你說(shuō)我怎么就攤上這事礁苗∨来眨” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵试伙,是天一觀的道長(zhǎng)贰谣。 經(jīng)常有香客問(wèn)我,道長(zhǎng)迁霎,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任百宇,我火速辦了婚禮考廉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘携御。我一直安慰自己昌粤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布啄刹。 她就那樣靜靜地躺著涮坐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪誓军。 梳的紋絲不亂的頭發(fā)上袱讹,一...
    開(kāi)封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音昵时,去河邊找鬼捷雕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛壹甥,可吹牛的內(nèi)容都是我干的救巷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼句柠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼浦译!你這毒婦竟也來(lái)了棒假?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤精盅,失蹤者是張志新(化名)和其女友劉穎帽哑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渤弛,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祝拯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了她肯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片佳头。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖晴氨,靈堂內(nèi)的尸體忽然破棺而出康嘉,到底是詐尸還是另有隱情,我是刑警寧澤籽前,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布亭珍,位于F島的核電站,受9級(jí)特大地震影響枝哄,放射性物質(zhì)發(fā)生泄漏肄梨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一挠锥、第九天 我趴在偏房一處隱蔽的房頂上張望众羡。 院中可真熱鬧,春花似錦蓖租、人聲如沸粱侣。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)齐婴。三九已至,卻和暖如春稠茂,著一層夾襖步出監(jiān)牢的瞬間柠偶,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工睬关, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嚣州,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓共螺,卻偏偏與公主長(zhǎng)得像该肴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子藐不,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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

  • 摘要 隨著中國(guó)股票市場(chǎng)的發(fā)展匀哄,市場(chǎng)中開(kāi)始出現(xiàn)了越來(lái)越多的股票秦效,各種行業(yè)概念的劃分開(kāi)始不斷出現(xiàn),而市場(chǎng)中最為流行的個(gè)...
    段公子閱讀 4,848評(píng)論 0 51
  • 綜述 我是一個(gè)投機(jī)客涎嚼。我的交易體系的核心為:價(jià)值選股阱州,技術(shù)擇時(shí),大波段操作法梯。 以下是我整理的一些前輩的心得苔货,對(duì)于我...
    KIKO_軟糖閱讀 4,364評(píng)論 0 4
  • 算法技術(shù)解構(gòu) 1、Python基礎(chǔ)知識(shí) (1)IPythonIPython的開(kāi)發(fā)者吸收了標(biāo)準(zhǔn)解釋器的基本概念立哑,在此...
    shenciyou閱讀 5,281評(píng)論 0 10
  • 2017.10.06 今天是國(guó)慶節(jié)假期夜惭,但是產(chǎn)科一樣要值班。一上午收了兩個(gè)病人铛绰,等到中午一點(diǎn)才吃到了午飯诈茧。還好下午...
  • 一、轉(zhuǎn)印芝士蛋糕 1.放松心情描邊捂掰,保持線條流暢敢会。 2.鉤邊裱花袋出口適宜,鉤邊線條粗一點(diǎn)这嚣。 3.填充顏色時(shí)裱花袋...
    一點(diǎn)甜Plus閱讀 1,155評(píng)論 5 1