if args.exitsignal is not None: cerebro.add_signal(bt.SIGNAL_LONGEXIT, SMAExitSignal, p1=args.exitperiod, p2=args.smaperiod) cerebro.add_signal(bt.SIGNAL_SHORTEXIT, SMAExitSignal, p1=args.exitperiod, p2=args.smaperiod)
def _next_signal(self): if self._sentinel is not None and not self.p._concurrent: return # order active and more than 1 not allowed
sigs = self._signals nosig = [[0.0]] # 第一部分:注册为多空市场的信号 # Calculate current status of the signals ls_long = all(x[0] > 0.0 for x in sigs[bt.SIGNAL_LONGSHORT] or nosig) ls_short = all(x[0] < 0.0 for x in sigs[bt.SIGNAL_LONGSHORT] or nosig) # 第二部分:注册为单看多市场的信号 l_enter0 = all(x[0] > 0.0 for x in sigs[bt.SIGNAL_LONG] or nosig) # >0表示看多 l_enter1 = all(x[0] < 0.0 for x in sigs[bt.SIGNAL_LONG_INV] or nosig) # _INV反向信号,<0,负数表示看多 l_enter2 = all(x[0] for x in sigs[bt.SIGNAL_LONG_ANY] or nosig) # _ANY只要非0就是true l_enter = l_enter0 or l_enter1 or l_enter2
s_enter0 = all(x[0] < 0.0 for x in sigs[bt.SIGNAL_SHORT] or nosig) s_enter1 = all(x[0] > 0.0 for x in sigs[bt.SIGNAL_SHORT_INV] or nosig) s_enter2 = all(x[0] for x in sigs[bt.SIGNAL_SHORT_ANY] or nosig) s_enter = s_enter0 or s_enter1 or s_enter2 # 第三部分:多头退出信号 l_ex0 = all(x[0] < 0.0 for x in sigs[bt.SIGNAL_LONGEXIT] or nosig) l_ex1 = all(x[0] > 0.0 for x in sigs[bt.SIGNAL_LONGEXIT_INV] or nosig) l_ex2 = all(x[0] for x in sigs[bt.SIGNAL_LONGEXIT_ANY] or nosig) l_exit = l_ex0 or l_ex1 or l_ex2
# 第四部分:空头退出信号 s_ex0 = all(x[0] > 0.0 for x in sigs[bt.SIGNAL_SHORTEXIT] or nosig) s_ex1 = all(x[0] < 0.0 for x in sigs[bt.SIGNAL_SHORTEXIT_INV] or nosig) s_ex2 = all(x[0] for x in sigs[bt.SIGNAL_SHORTEXIT_ANY] or nosig) s_exit = s_ex0 or s_ex1 or s_ex2
# Use oppossite signales to start reversal (by closing) # but only if no "xxxExit" exists # self._longexit=bool(_obj._signals[bt.SIGNAL_LONGEXIT]) # 未设置独立的多头退出信号,且空头进入信号为true,long_reverse信号为true l_rev = not self._longexit and s_enter # 未设置独立的空头退出信号,且多头进入信号为true,short_reverse信号为true s_rev = not self._shortexit and l_enter
# 这一部分是第一部分的反信号 # Opposite of individual long and short l_leav0 = all(x[0] < 0.0 for x in sigs[bt.SIGNAL_LONG] or nosig) l_leav1 = all(x[0] > 0.0 for x in sigs[bt.SIGNAL_LONG_INV] or nosig) l_leav2 = all(x[0] for x in sigs[bt.SIGNAL_LONG_ANY] or nosig) l_leave = l_leav0 or l_leav1 or l_leav2 # 这一部分是第二部分的反信号 s_leav0 = all(x[0] > 0.0 for x in sigs[bt.SIGNAL_SHORT] or nosig) s_leav1 = all(x[0] < 0.0 for x in sigs[bt.SIGNAL_SHORT_INV] or nosig) s_leav2 = all(x[0] for x in sigs[bt.SIGNAL_SHORT_ANY] or nosig) s_leave = s_leav0 or s_leav1 or s_leav2 # 未设置独立的多头退出信号,且多头leave为true # Invalidate long leave if longexit signals are available l_leave = not self._longexit and l_leave # 未设置独立的空头退出信号,且空头leave为true # Invalidate short leave if shortexit signals are available s_leave = not self._shortexit and s_leave
# Take size and start logic size = self.getposition(self._dtarget).size if not size: # 没有持仓,只能开仓操作,判断是否有满足的开仓条件 if ls_long or l_enter: self._sentinel = self.buy(self._dtarget)
elif ls_short or s_enter: self._sentinel = self.sell(self._dtarget)
elif size > 0: # current long position,当前多头持仓,判断是否满足平仓,开空仓条件 if ls_short or l_exit or l_rev or l_leave: # closing position - not relevant for concurrency self.close(self._dtarget)
if ls_short or l_rev: self._sentinel = self.sell(self._dtarget)
if ls_long or l_enter: if self.p._accumulate: self._sentinel = self.buy(self._dtarget)
elif size < 0: # current short position,当前空头持仓,判断是否满足平仓,开多仓条件 if ls_long or s_exit or s_rev or s_leave: # closing position - not relevant for concurrency self.close(self._dtarget)
if ls_long or s_rev: self._sentinel = self.buy(self._dtarget)
if ls_short or s_enter: if self.p._accumulate: self._sentinel = self.sell(self._dtarget)
这一部分逻辑看起来有点难以理解,先只考虑单向做多市场相关信号,分3类: 第一类:多头进入信号(开仓信号),l_enter = l_enter0 or l_enter1 or l_enter2 第二类:多头退出信号(平仓信号),l_exit = l_ex0 or l_ex1 or l_ex2 第三类:多头进入非有效(失效)信号,l_leave = l_leav0 or l_leav1 or l_leav2 关于第一类,第二个类信号,非常显著, l_enter只关联self.buy(self._dtarget) l_exit只关联了self.close(self._dtarget) 而l_leave和l_exit类似,只关联了self.close(self._dtarget),所以l_leave和l_exit可看做邻近信号,二者或的关系(实际上,只会有一个有效,因为leave信号生效前提是未设置专用的 exit信号,而exit类信号必须是设置了专用exit信号)。
longshort类型交易,面对金叉和死叉会形成点状持仓还是状态持仓
代码:
1 2 3 4 5 6 7 8 9 10
class TestCrossover(bt.Indicator): lines = ('signal',) params = (('pfast', 5),('pslow', 20))
当前时点(今日):datetime 2019-01-02 close 51.12077805 往前推1天(昨日):datetime 2021-01-28 close 54.91980265 往前推2天(前日) datetime 2021-01-27 close 55.5952978 注意:此处时间循环了,应该19年的,取到了21年。
#返回股价低于2元的股票个数占比 def f1(self,date_list): bei = len(date_list)//13 se_price_2 = [] for i in range(1,13): e = date_list[i*bei] s = date_list[(i-1)*bei] if i == 0: s = date_list[0] elif i == 12: e = date_list[-1] all_stock = list(get_all_securities(types='stock',date=e).index) def f1_1(x): x=x.dropna(axis=0) return sum(x) df = get_price(all_stock,start_date=s,end_date=e,fields=['close'],fq=None)['close'] df_1 = df<=2*(1.04)**i #print(2*(1.04)**i) se1 = df_1.apply(f1_1,axis=1) l2 = [len(get_all_securities(types='stock',date=i)) for i in se1.index ] se2 = pd.Series(l2,index=se1.index) #se2 = df_1.apply(f1_1[1],axis=1) se_price_2.append(se1/se2) return pd.concat(se_price_2)
# 统计各个定投时间对应的收益情况 periodic_profit=[set() for i in range(profit_df.shape[0])] # 将profit_df中的value填充到periodic_profit对应定投时长的set集合中 for x in range(profit_df.shape[0]): for y in range(x+1,profit_df.shape[1]): periodic_profit[y-x].add(profit_df.iloc[x,y])
# change01:profit=>profit_rate periodic_profit_df=pd.DataFrame(columns=['priod','profit']) # periodic_profit_df=pd.DataFrame(columns=['priod','profit_rate']) for i in range(len(periodic_profit)): if periodic_profit[i]: for x in periodic_profit[i]: periodic_profit_df.loc[len(periodic_profit_df)] = [int(i),x] periodic_profit_df.tail()