def recalc_paramter(self): try: # 平均真实波幅(N值) self.n = ATR(self.klines, self.atr_day_length)["atr"].iloc[-1] # 买卖单位 #: 账户权益 (账户权益 = 动态权益 = 静态权益 + 平仓盈亏 + 持仓盈亏 - 手续费 + 权利金 + 期权市值) self.unit = max( int((self.account.available * 0.06) / (self._quote.volume_multiple * self.n)), 0) margin_ratio = 0.1 while self.unit > 0: if self.unit * margin_ratio * self._quote.last_price * self._quote.volume_multiple < self.account.available: break else: # 调整unit的之 self.unit -= 1 # 唐奇安通道上轨:前N个交易日的最高价 self.donchian_channel_high = max( self.klines.high[-self.donchian_channel_open_position - 1:-1]) # 唐奇安通道下轨:前N个交易日的最低价 self.donchian_channel_low = min( self.klines.low[-self.donchian_channel_open_position - 1:-1]) # logger.info("账户可用资金 %f " % self.account.available) logger.info( "Pos:%4s,Last_price:%9.2f,Inst:%12s 上下轨:%8s, %8s N值: %6.2f Unit:%4s 可用:%10.2f,QuoteTime:%s" % (self.state['position'], self.state['last_price'], self._symbol, self.donchian_channel_high, self.donchian_channel_low, self.n, self.unit, self.account.available, self._quote.datetime)) return True except Exception as e: logger.info(e) return False
def get_open(signal): klines = api.get_kline_serial( 品种, period, ) quote = api.get_quote(品种) atr = ATR(klines, 30) TR1 = atr.tr ATR1 = atr.atr #print(ATR1.values) kl = klines.set_index("datetime") yes = api.get_kline_serial(品种, 60 * 60 * 24) time1 = yes.datetime.iloc[-1] day_num = yes.datetime.iloc[-1] - yes.datetime.iloc[-2] print(day_num) NN = len(klines[(klines['datetime'] > time1) & (klines['datetime'] < time1 + day_num)]) print('NN', NN) H1 = ref(hhv(klines.high, NN), NN) #昨序列 print(klines.high) print("HHV", hhv(klines.high, NN)) print("H1", H1) L1 = ref(llv(klines.low, NN), NN) O2 = klines[(klines['datetime'] > time1) & (klines['datetime'] < time1 + day_num)].iloc[0].open print(O2) if (ATR1.values[-1] > 21): print('hhaha', ATR1.values[-1]) KK1 = 3 else: KK1 = 5 if (ATR1.values[-1] > 21): KK2 = 3 else: KK2 = 5 HH = O2 + (H1 - L1) * KK1 * 0.1 print("____________H1-L1", H1 - L1) print("HH:", HH, type(HH)) LL = O2 - (H1 - L1) * KK2 * 0.1 print('LL', LL) DAYBARPOS = len(klines[klines['datetime'] > time1]) print("daybarpos", DAYBARPOS) HH1 = hhv(klines.high, DAYBARPOS) LL1 = llv(klines.low, DAYBARPOS) UU = HH - LL print("HH1:", HH1) C = quote.close KDTJ = all( ((C >= HH).values[-1], (H1 != L1).values[-1], llv(klines.low, NN) > (O2 - (H1 - L1) * KK1 * 0.1), UU < 55, UU > 15)) KKTJ = all((C <= HH, H1 != L1, hhv(klines.high, NN) < (O2 + (H1 - L1) * KK1 * 0.1), UU < 55, UU > 15)) SP_1 = all((TR1 > 18, klines.low <= O2 - (H1 - L1) * 8 * 0.1)) BP_1 = all((TR1 > 18, klines.high >= O2 + (H1 - L1) * 8 * 0.1)) dict1 = {"KDTJ": KDTJ, "KKTJ": KKTJ, "SP": SP_1, "BP": BP_1} return dict1[signal]
def trend_line(self, kline_level="day", atr_n=14, MA_n=40): ''' 趋势线策略 ''' # profit_space_switch = { # "day":lambda n: ATR(self.api.get_kline_serial(self.symbol, 60*60*24), n), # "hour":lambda n: ATR(self.api.get_kline_serial(self.symbol, 60*60), n) # } # loss_space_switch = { # "day":lambda n: ATR(self.api.get_kline_serial(self.symbol, 60*60), n), # "hour":lambda n: ATR(self.api.get_kline_serial(self.symbol, 5*60), n) # } # loss_space = loss_space_switch[self.kline_level](atr_n) # profit_space = profit_space_switch[self.kline_level](atr_n) trend = 0 # 1 上升趋势,0 震荡, -1 下降趋势 quote = self.api.get_quote(self.symbol) target = TargetPosTask(self.api, self.symbol) if kline_level == "day": loss_atr_period = 60 * 60 profit_atr_period = 24 * 60 * 60 trend_period = 24 * 60 * 60 trend_kline = self.api.get_kline_serial(self.symbol, trend_period) elif kline_level == "week": loss_atr_period = 60 * 60 profit_atr_period = 7 * 24 * 60 * 60 trend_period = 24 * 60 * 60 loss_space = ATR( self.api.get_kline_serial(self.symbol, loss_atr_period), atr_n) profit_space = ATR( self.api.get_kline_serial(self.symbol, profit_atr_period), atr_n) if trend_kline.iloc[-1].close > MA( trend_kline, 40).iloc[-1] + 2 * ATR(trend_kline, atr_n): trend = 1 while True: pass
def recalc_paramter(self): # 平均真实波幅(N值) self.n = ATR(self.klines, self.atr_day_length)["atr"].iloc[-1] # 买卖单位 self.unit = int((self.account.balance * 0.01) / (self.quote.volume_multiple * self.n)) # 唐奇安通道上轨:前N个交易日的最高价 self.donchian_channel_high = max( self.klines.high[-self.donchian_channel_open_position - 1:-1]) # 唐奇安通道下轨:前N个交易日的最低价 self.donchian_channel_low = min( self.klines.low[-self.donchian_channel_open_position - 1:-1]) print("唐其安通道上下轨: %f, %f" % (self.donchian_channel_high, self.donchian_channel_low)) return True
def ThetaATR(self, df, n): upper = 6 # 上轨 mid = 5 # 中轨 lower = 4 # 下轨 atr = ATR(df, n) # 标准化,每根柱子ATR 设置为5,得出比例 ratio = atr.atr / mid # 算出thetaATR thetaATR = atr.tr / ratio print(thetaATR) plt.hlines(upper, 0, 200, colors="r") plt.hlines(mid, 0, 200, colors='y') plt.hlines(lower, 0, 200, colors='b') plt.plot(thetaATR.index, thetaATR.values) plt.plot(df["close"] / 500) plt.show()
def get_daybar_score(self, klines, id): self.debug("======analyze [%s] daybar=========" % (tafunc.time_to_str(klines.iloc[-id].datetime))) self.debug("当日:open=%d close=%d" % (klines.iloc[-1].open, klines.iloc[-1].close)) self.debug("昨日:open=%d close=%d" % (klines.iloc[-id].open, klines.iloc[-id].close)) #突破+40 #Bigbang30 #连续+10 #震荡上一个绿+10 #底部+10 BreakScore = 30 BigBangScore = 20 CheckSumScore = 20 ContinueScore = 10 InRangeAdjust = 10 TopBomScore = 10 RED_GREEN_SCORE = 10 self.kpi = 0 self.cur_day_bar = id if (self.cur_price == 0): self.cur_price = klines.iloc[-id].close #常用数据 atr = ATR(klines, 30) self.ATR_day = int(atr.atr.iloc[-id]) print("[%s] self.ATR_day=%d" % (self.TAG, self.ATR_day)) # big bang find self.last_big_green_candle, self.last_big_green_candle_hight = pplib.find_big_green_candle( klines, 1, id, id + 20, atr.atr.iloc[-id] * 1.5) self.last_big_red_candle, self.last_big_red_candle_height = pplib.find_big_red_candle( klines, 1, id, id + 20, atr.atr.iloc[-id] * 1.5) # big bang score if (self.last_big_red_candle - id < 10 and self.last_big_red_candle < self.last_big_green_candle): self.kpi = self.kpi + (11 - (self.last_big_red_candle - id)) * ( BigBangScore / 10) + int( (self.last_big_red_candle - atr.atr.iloc[-id] * 1.5) / 50) * 5 if (self.last_big_green_candle - id < 10 and self.last_big_red_candle < self.last_big_green_candle): self.kpi = self.kpi - (11 - (self.last_big_green_candle - 1)) * ( BigBangScore / 10) - int( (self.last_big_red_candle - atr.atr.iloc[-id] * 1.5) / 50) * 5 print( "[%s] self.last_big_red_candle=%d, self.last_big_green_candle=%d" % (self.TAG, self.last_big_red_candle, self.last_big_green_candle)) print("[%s] kpi=%d" % (self.TAG, self.kpi)) #continue find self.last_continue_up_bar = 999 self.last_continue_down_bar = 999 for i in range(id, id + 6): count = 0 for j in range(0, 3): if (klines.iloc[-(i + j)].open < klines.iloc[-(i + j)].close): count = count + 1 else: count = count - 1 if (count >= 3): self.last_continue_up_bar = i break elif (count <= -3): self.last_continue_down_bar = i break #连续 if (self.last_continue_up_bar - id <= 1): self.kpi = self.kpi + ContinueScore if (self.last_continue_down_bar - id <= 1): self.kpi = self.kpi - ContinueScore print( "[%s] self.last_continue_up_bar=%d self.last_continue_down_bar=%d" % (self.TAG, self.last_continue_up_bar, self.last_continue_down_bar)) print("[%s] kpi=%d after ContinueScore" % (self.TAG, self.kpi)) #checksum self.day_checksum_4 = pplib.get_checksum(klines, 5, 1) cks_ret = abs(self.day_checksum_4) / self.ATR_day print("[%s] self.day_checksum_4=%d cks_ret=%f" % (self.TAG, self.day_checksum_4, cks_ret)) cks_score = 0 cks_weight = 0.2 if (cks_ret > 1.5): cks_weight = 1 elif (cks_ret > 1): cks_weight = 0.7 elif (cks_ret > 0.5): cks_weight = 0.5 else: cks_weight = 0.2 if (self.day_checksum_4 > 0): cks_score = int(CheckSumScore * cks_weight) if (self.day_checksum_4 < 0): cks_score = -int(CheckSumScore * cks_weight) print("[%s] cks_score=%d" % (self.TAG, cks_score)) # inrange find heightest = 1000 heightest_bar = 1 ''' for i in range(id, id+2): height = pplib.get_height_in_range(klines, i, i+3) if (height > heightest): heightest = height heightest_bar = i ''' heightest = pplib.get_height_in_range(klines, id, id + 5) result = heightest / atr.atr.iloc[-i] print("[%s] result=%f" % (self.TAG, result)) if (result < 1.5): self.last_inrange_bar = heightest_bar self.last_inrange_height = heightest self.last_inrange_high = pplib.get_hest_in_range(klines, id, id + 5) self.last_inrange_low = pplib.get_lest_in_range(klines, id, id + 5) #inrange score if (self.last_inrange_bar - id < 2 and self.last_continue_up_bar - id > 3 and self.last_continue_down_bar - id > 3): if (klines.iloc[-id].close > klines.iloc[-id].open): self.kpi = self.kpi - InRangeAdjust else: self.kpi = self.kpi - InRangeAdjust print("[%s] last_inrange_bar=%d" % (self.TAG, self.last_inrange_bar)) self.debug( "last_inrange_high=%d last_inrange_low=%d last_inrange_height=%d" % (self.last_inrange_high, self.last_inrange_low, self.last_inrange_height)) print("[%s] kpi=%d" % (self.TAG, self.kpi)) #===================================================# # break find self.last_break_up_bar = 999 self.last_break_down_bar = 999 for i in range(id, id + 6): tmp = pplib.get_hest_in_range(klines, i + 1, i + 1 + 4) if (klines.iloc[-i].close > tmp): self.last_break_up_bar = i break for i in range(id, id + 6): tmp = pplib.get_lest_in_range(klines, i + 1, i + 1 + 4) if (klines.iloc[-i].close < tmp): self.last_break_down_bar = i break #break if (self.last_break_up_bar - id == 0): self.kpi = self.kpi + BreakScore elif (self.last_break_up_bar - id == 1): self.kpi = self.kpi + int(BreakScore / 2) elif (self.last_break_up_bar - id == 2): self.kpi = self.kpi + int(BreakScore / 3) if (self.last_break_down_bar - id == 0): self.kpi = self.kpi - BreakScore elif (self.last_break_down_bar - id == 1): self.kpi = self.kpi - int(BreakScore / 2) elif (self.last_break_down_bar - id == 2): self.kpi = self.kpi - int(BreakScore / 3) print("[%s] self.last_break_up_bar=%d self.last_break_down_bar=%d " % (self.TAG, self.last_break_up_bar, self.last_break_down_bar)) print("[%s] kpi=%d" % (self.TAG, self.kpi)) #=====================================# # price pos find self.hh_100, self.hh_100_bar = pplib.get_hest_in_range2( klines, id, id + 100) self.ll_100, self.ll_100_bar = pplib.get_lest_in_range2( klines, id, id + 100) price_pos_ratio = (self.cur_price - self.ll_100) / (self.hh_100 - self.ll_100) if (price_pos_ratio <= 0.5): self.kpi = self.kpi + (5 - int(price_pos_ratio * TopBomScore)) * 2 else: self.kpi = self.kpi - (int(price_pos_ratio * TopBomScore) - 5) * 2 print("[%s] price_pos_ratio=%f" % (self.TAG, price_pos_ratio)) print("[%s] kpi=%d" % (self.TAG, self.kpi)) #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# #修正 if (self.last_break_up_bar - id <= 2 and self.last_big_red_candle - id < 6): print("last_break_up_bar=%d last_big_red_candle=%d " % (self.last_break_up_bar - id <= 2, self.last_big_red_candle - id)) self.kpi += 20 if (self.last_break_down_bar - id <= 2 and self.last_big_green_candle - id < 6): self.kpi -= 20 if (self.last_break_up_bar - id <= 2 and price_pos_ratio < 0.6): self.kpi += 20 print("last_break_up_bar=%d price_pos_ratio=%d " % (self.last_break_up_bar - id <= 2, price_pos_ratio)) if (self.last_break_down_bar - id <= 2 and self.last_big_green_candle - id < 6): self.kpi -= 20 #print ("height=%d atr=%d wave ratio=%f "%(height, atr.atr.iloc[-i], height/atr.atr.iloc[-i])) print("[%s] kpi=%d" % (self.TAG, self.kpi)) #=====================================================================# # 距离底、顶的距离 self.hh_20, self.hh_20_bar = pplib.get_hest_in_range2( klines, id, id + 20) self.ll_20, self.ll_20_bar = pplib.get_lest_in_range2( klines, id, id + 20) self.hh_10, self.hh_10_bar = pplib.get_hest_in_range2( klines, id, id + 10) self.ll_10, self.ll_10_bar = pplib.get_lest_in_range2( klines, id, id + 10) self.hh_5, self.hh_5_bar = pplib.get_hest_in_range2(klines, id, id + 6) self.ll_5, self.ll_5_bar = pplib.get_lest_in_range2(klines, id, id + 6) dif = self.hh_10_bar - id if (dif == 0): self.kpi += TopBomScore if (dif == 1): self.kpi += int(TopBomScore / 2) elif (dif == 2): self.kpi -= TopBomScore elif (dif == 3): self.kpi += TopBomScore elif (dif > 3 and dif <= 5): self.kpi -= TopBomScore self.to_top = dif dif = self.ll_10_bar - id if (dif == 0): self.kpi -= TopBomScore if (dif == 1): self.kpi -= int(TopBomScore / 2) elif (dif == 2): self.kpi += TopBomScore elif (dif == 3): self.kpi -= TopBomScore elif (dif > 3 and dif <= 5): self.kpi += TopBomScore self.to_bottom = dif print("[%s] to top=%d, to bottom=%d " % (self.TAG, self.hh_10_bar - id, self.ll_10_bar - id)) print("[%s] kpi=%d" % (self.TAG, self.kpi)) #==============================================================# # 红绿数量 red_gre_score = 0 self.reds = pplib.get_reds_candle(klines, 6) self.greens = pplib.get_greens_candle(klines, 6) if (self.greens > 0): red_gre_score -= self.greens * 20 if (self.reds > 0): red_gre_score += self.reds * 20 self.kpi += red_gre_score * (RED_GREEN_SCORE / 100) #跳空 print("[%s] greens=%d reds=%d" % (self.TAG, self.greens, self.reds)) gap_v = klines.iloc[-id].open - klines.iloc[-(id + 1)].close if (gap_v > 10): print("[%s] 高跳" % (self.TAG)) self.manager.drive_event(self.TAG, StgEvent.GapUp, gap_v) self.kpi += 10 gap_v = klines.iloc[-(id + 1)].close - klines.iloc[-id].open if (gap_v > 10): print("[%s] 低跳" % (self.TAG)) self.manager.drive_event(self.TAG, StgEvent.GapDown, gap_v) self.kpi -= 10 print("[%s] kpi=%d" % (self.TAG, self.kpi))
def preparse_dayline_trend(self, d_klines): back_count = 6 red_count = 0 checksum = 0 atr = ATR(d_klines, 30) self.atr_daily = int(atr.atr.iloc[-1]) #print(self.TAG, self.atr_daily) # 平均真实波幅 for i in range(1, back_count): if (d_klines.iloc[-i].open - d_klines.iloc[-i].close > 0): red_count = red_count + 1 checksum = checksum + (d_klines.iloc[-i].close - d_klines.iloc[-i].open) weight = tafunc.abs(checksum) / atr.atr.iloc[-i] print("[%s] parse_dayline_trend checksum=%d weight=%f " % (self.TAG, checksum, weight)) #if (checksum > 0 and checksum > back_count*atr.atr): self.day_trend = red_count - (back_count - red_count) if (float(weight) > float(0.001) and checksum > 0): self.day_trend = self.day_trend + weight if (float(weight) > float(0.001) and checksum < 0): self.day_trend = self.day_trend - weight # 关键 #range_H = tafunc.hhv(klines.high, 5) #range_L = tafunc.llv(klines.low, 5) self.Long_HH = pplib.get_hest_in_range(d_klines, 1, 50) self.Long_LL = pplib.get_lest_in_range(d_klines, 1, 50) self.range_HH, self.hh_day_bar = get_hh_price_bar(d_klines, 5) self.range_LL, self.ll_day_bar = get_ll_price_bar(d_klines, 5) print("[%s] Long_HH=%d Long_LL=%f " % (self.TAG, self.Long_HH, self.Long_LL)) # 大小口 配合 self.support_line = get_support_line(d_klines, 1, 2, 10) self.resistance_line = get_resistance_line(d_klines, 1, 2, 10) # 敏感价格基于前长周期的波峰波谷,后期被打破或形成支撑阻力 self.sensitive_hh_bar, self.sensitive_hh = get_sensitive_hh( d_klines, 2) self.sensitive_ll_bar, self.sensitive_ll = get_sensitive_ll( d_klines, 2) self.debug("support_line=%d resistance_line=%d" % (self.support_line, self.resistance_line)) self.debug( "sensitive_hh_bar=%d sensitive_hh=%d sensitive_ll_bar=%d sensitive_ll=%d" % (self.sensitive_hh_bar, self.sensitive_hh, self.sensitive_ll_bar, self.sensitive_ll)) if (self.sensitive_hh != 0): self.set_indor_value(Indicator.RangeHDaily, self.sensitive_hh) if (self.sensitive_ll != 0): self.set_indor_value(Indicator.RangeLDaily, self.sensitive_ll) # 关键,需手动录入 ''' self.key_hh = self.key_ll = ''' ''' 日线级别的均线值 ''' self.ma10 = 0 self.ma20 = 0 ''' 预估 ''' self.forecast = 0 for i in range(1, 5): self.lastday_quote.append(d_klines.iloc[-i]) self.debug("last_day: open=%d close=%d high=%d low=%d" % (self.lastday_quote[1].open, self.lastday_quote[1].close, self.lastday_quote[1].high, self.lastday_quote[1].low)) return self.day_trend
def on_day_bar(self, dklines): start_id = 2 #find_range #自然波动区间 #强势后整理波动区间 #find_strong_price self.support_ll = 0 self.resistance_hh = 0 self.range_hh = 0 self.range_ll = 0 self.boll_top = 0 self.boll_bottom = 0 self.trade_ll = 0 self.trade_hh = 0 atr = ATR(dklines, 30) self.atr_daily = int(atr.atr.iloc[-1]) #如果区间线和强势线重合,确定方向 inrange_result = self.find_inrange_daily(start_id, dklines) #支撑、阻力 strong_result = self.find_strong_daliy(start_id, dklines) # boll self.find_boll_daily(start_id, dklines) if (inrange_result == True or strong_result == True): if (self.support_ll!=0 and self.range_ll!=0): self.trade_ll = int((self.range_ll + self.support_ll)/2) elif(self.support_ll != 0): self.trade_ll = self.support_ll elif(self.range_ll != 0): self.trade_ll = self.range_ll if (self.resistance_hh!=0 and self.range_hh!=0): self.trade_hh = int((self.range_hh + self.resistance_hh)/2) elif(self.resistance_hh != 0): self.trade_hh = self.resistance_hh elif(self.range_hh != 0): self.trade_hh = self.range_hh self.trend_type_daily = TrendType.WAVE if (self.support_ll!=0 and self.resistance_hh!=0): self.set_trade_direction(TradeDirection.BUYSELL) elif (self.support_ll != 0): self.set_trade_direction(TradeDirection.BUYONLY) elif(self.resistance_hh != 0): self.set_trade_direction(TradeDirection.SELLONLY) if (self.trade_hh == 0): self.trade_hh = self.boll_top if (self.trade_ll == 0): self.trade_ll = self.boll_bottom else: self.trend_type_daily = TrendType.TREND self.trade_ll = self.boll_bottom self.trade_hh = self.boll_top self.debug("on_day_bar trade_hh=%d trade_ll=%d"%(self.trade_hh, self.trade_ll)) self.hh_3day = pplib.get_hest_in_range(dklines, start_id, start_id+3) self.ll_3day = pplib.get_lest_in_range(dklines, start_id, start_id+3) self.debug("on_day_bar hh_3day=%d ll_3day=%d"%(self.hh_3day, self.ll_3day)) self.hh_50day = pplib.get_hest_in_range(dklines, start_id, start_id+50) self.ll_50day = pplib.get_lest_in_range(dklines, start_id, start_id+50)
# SYMBOL = "SHFE.au1912" code_index = "wr" SYMBOL = SYMBOL_JSON[code_index]["symbol"] ## 合约代码 VALUE = SYMBOL_JSON[code_index]["contractSize"] ## 合约乘数 api = TqApi(web_gui=True,backtest=TqBacktest(start_dt=date(2000, 5, 1), end_dt=date(2019, 12, 31))) # klines = api.get_kline_serial(SYMBOL, 60*5) ## 60*5=50分钟 klines = api.get_kline_serial(SYMBOL, 60*60*24) ## 60*60*24=日线 print("datetime","open","high","low","close","volume","tmpvol_hl","maxvol_hl","tmpvol_oc","maxvol_oc","minvol_oc","ma","atr","bollmatitude","rsi","atr/ma","atrMoney") maxvol_hl = 0 maxvol_oc = 0 minvol_oc = 0 while True: # 通过wait_update刷新数据 api.wait_update() atr = ATR(klines,14) boll = BOLL(klines, 14 , 2) rsi = RSI(klines,14) lastKline = klines.iloc[-1] tmpvol_hl=lastKline.high-lastKline.low tmpvol_oc=lastKline.close-lastKline.open maxvol_oc = max(maxvol_oc,lastKline.close-lastKline.open) minvol_oc = min(minvol_oc,lastKline.close-lastKline.open) maxvol_hl = max(maxvol_hl,lastKline.high-lastKline.low) midline = boll["mid"].iloc[-1] topline = boll["top"].iloc[-1] bottomline = boll["bottom"].iloc[-1] bollmatitude = topline-bottomline atr_ma = 0 if(midline>0): atr_ma = atr.atr.iloc[-1] / midline
#下面是回测用api,实盘时候记得注释掉。 api = TqApi(TqSim(200000), backtest=TqBacktest(start_dt=date(2019, 7, 15), end_dt=date(2020, 1, 15)), web_gui="http://127.0.0.1:61000/") #接收行情设置持仓目标 klines = api.get_kline_serial(SYMBOL, 60 * 60 * 24) # 1小时K线 klines_long = api.get_kline_serial(SYMBOL, 60 * 60 * 24) # 日K线 quote = api.get_quote(SYMBOL) position = api.get_position(SYMBOL) target_pos = TargetPosTask(api, SYMBOL) # 使用BOLL指标计算中轨、上轨和下轨,其中26为周期N ,2为参数p atr = ATR(klines, 26) midline = tafunc.ema2(klines.close, MA_FAST) topline = midline + atr.atr bottomline = midline - atr.atr #print("策略运行,中轨:%.2f,上轨为:%.2f,下轨为:%.2f" % (midline, topline, bottomline)) while True: api.wait_update() # 每次生成新的K线时重新计算BOLL指标 if api.is_changing(klines.iloc[-1], "datetime") or api.is_changing( quote, "last_price"): atr.atr = ATR(klines, 26) midline = tafunc.ema2(klines.close, MA_FAST) topline = midline + atr.atr