置顶 聚宽 指数轮动策略复现
发布于 7 个月前 作者 vensentzhou 1003 次浏览 来自 分享

聚宽有一篇关于三指数轮动的策略https://www.joinquant.com/post/27798,简单说就是比较沪深300,创业板,中证500 指数的涨幅,谁强势就买谁。效果还不错。于是想在QA中复现。因为QAStratage暂时没有对ETF基金支持,所有需要修改些代码,我不会RP,所有只好在帖子里简单标注一下修改了那几个文件: image.png 因为30分钟数据的原因,回测只是从2018年7月开始,回测结果如图: image.png 最后上代码: ’’' import QUANTAXIS as QA from qastockbase_etf import QAStrategyStockBase from QUANTAXIS.QAUtil.QAParameter import MARKET_TYPE import pandas as pd import pymongo from qaenv import (eventmq_amqp, eventmq_ip, eventmq_password, eventmq_port, eventmq_username, mongo_ip, mongo_uri) from QARisk import QA_Risk from QAUser import QA_User

class Strategy(QAStrategyStockBase):

def debug(self):
    self.running_mode = 'backtest'
    self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS
    user = QA_User(username="admin", password='admin')
    port = user.new_portfolio(self.portfolio)
    self.acc = port.new_accountpro(
        account_cookie=self.strategy_id, init_cash=self.init_cash, market_type=self.market_type, frequence= self.frequence)
    #self.positions = self.acc.get_position(self.code)

    print(self.acc)

    print(self.acc.market_type)
    data = QA.QA_quotation(self.code, self.start, self.end, source=QA.DATASOURCE.MONGO,
                           frequence=self.frequence, market=self.market_type, output=QA.OUTPUT_FORMAT.DATASTRUCT)
    #挑选符合条件的历史时点数据
    df=data.data
    df.reset_index(inplace=True)
    df=df.assign(time=df.datetime.apply(lambda x:str(x)[11:]))
    df=df.loc[df.time=='14:30:00'].set_index(['datetime','code'])
    data.data=df
    print('回测数据:')
    print(data.data)
    data.data.apply(self.x1, axis=1)

def on_bar(self,data):
    #print('*'*10)
    #print(data)
    #print(self.get_positions(data.name[1]))
    # print(self.market_data)
    if len(self.get_current_marketdata())==len(self.code) and str(self.market_datetime[-1])[11:]=='14:30:00':
        print('当前时间:')
        print(self.market_datetime[-1])
        
        df=QA.QA_DataStruct_Index_min(self.market_data)
        
        ind=df.add_func(select_etf)
        
        time_data=ind[-len(self.code):].sort_values(by='change')
        # print(time_data)
        code=time_data.iloc[-1].name[1]
        # print('排名第一的是:',code)
        price=self.get_current_marketdata().loc[(slice(None),time_data.iloc[-1].name[1]),'close'][0]
        # print('价格为:',price)
        # print('排序最大值:')
        # print(time_data.max()[0])
        print('当前持仓:')
        print(self.acc.hold_available)
        if time_data.max()[0]>0:
            if len(self.acc.hold_available)==0:# 如果没有持仓,买入排名第一的股票
                print('可用资金:',self.acc.cash_available)
                # self.send_order('BUY','OPEN',code=code,price=price,volume=10000)
                money=self.acc.cash_available
                self.send_order('BUY','OPEN',code=code,price=price,volume=get_volume_buy(price=price,money=money))
            elif self.acc.get_position(code).volume_long !=0:#如果持仓标的继续排名第一,则继续持有
                print('持仓标的持续强势,继续持有!')
            else:
                temp_s=self.acc.hold_available
                code_sell=temp_s.index[0]
                # print(code_sell)
                price_sell=self.get_current_marketdata().loc[(slice(None),code_sell),'close'][0]
                # print('卖出持仓,买入强势股')
                # print('调仓前可用资金:',self.acc.cash_available)
                self.send_order('SELL','CLOSE',code=code_sell,price=price_sell,volume=int(temp_s.loc[code_sell]))#卖出的时候 数量要加int
                # print('调仓前卖出股票后可用资金:',self.acc.cash_available)
                # self.send_order('BUY','OPEN',code=code,price=price,volume=10000)
                money=self.acc.cash_available
                self.send_order('BUY','OPEN',code=code,price=price,volume=get_volume_buy(price=price,money=money))
        else:
            if len(self.acc.hold_available)!=0:# 如果有持仓,卖出所有的股票
                temp_s=self.acc.hold_available
                code_sell=temp_s.index[0]
                print(code_sell)
                price_sell=self.get_current_marketdata().loc[(slice(None),code_sell),'close'][0]
                print('所有标的均下跌,清仓!!!!')
                # print('调仓前可用资金:',self.acc.cash_available)
                self.send_order('SELL','CLOSE',code=code_sell,price=price_sell,volume=int(temp_s.loc[code_sell]))#卖出的时候 数量要加int
                # print('调仓后可用资金:',self.acc.cash_available)
            else:
                print('所有标的均下跌,暂不买入')
    print('当日持仓:')
    print(self.acc.hold_available)   

def get_volume_buy(price,money): ’’‘计算可买数量,这里考虑到手续费和税的问题,所有只用98%的可用资金’’' volume=int(money0.98/price//100100) return volume

def select_etf(data): ’’‘因为前面已经做了历史数据筛选,这里只需要按天计算长度就可以了’’' close=data.close change=close.pct_change(5) return(pd.DataFrame({‘change’:change})) if name == “main”: code=[ ‘510500’,‘159915’,‘510300’]

s=Strategy(code, frequence='30min', start='2018-07-14', end='2020-07-10',market_type=MARKET_TYPE.INDEX_CN, strategy_id='rank_etf_30min_now_1c')

data=QA.QA_fetch_index_min_adv(code,'2018-07-04','2018-07-13','30min').data
df=data.reset_index()
df=df.assign(time=df.datetime.apply(lambda x:str(x)[11:]))
data=df.loc[df.time=='14:30:00'].set_index(['datetime','code'])
print('历史追加数据:')
print(data)
s._market_data=[data.iloc[i] for i in range(len(data))]
s.run_backtest()
'''
6 回复

缺少修改过的文件代码啊,也一起贴上来吧。

qastockbase_etf.py

学习了,感谢!!!

market_type=MARKET_TYPE.STOCK_CN就能回测成功,market_type=MARKET_TYPE.INDEX_CN则没有成交。不知道怎么回事?

qastockbase_etf找不到这个模块

回到顶部