Esempio n. 1
0
class Kline:
    def __init__(self):
        config.loads('config.json')
        self.symbol = "BTC-USDT-SWAP"
        self.timeframe = "1m"
        self.exchange = BINANCESWAP("", "", self.symbol)
        self.indicators = INDICATORS(self.exchange, self.symbol,
                                     self.timeframe)

    def update(self):
        table = self.exchange.get_kline(self.timeframe)
        table.reverse()
        try:
            df = pd.DataFrame(
                table,
                columns='time open high low close volume currency_volume'.
                split())
            df = df.astype({
                'time': 'datetime64[ns]',
                'open': 'float64',
                'high': 'float64',
                'low': 'float64',
                'close': 'float64',
                'volume': 'float64',
                'currency_volume': 'float64'
            })
        except:
            df = pd.DataFrame(
                table, columns='time open high low close volume'.split())
            df = df.astype({
                'time': 'datetime64[ns]',
                'open': 'float64',
                'high': 'float64',
                'low': 'float64',
                'close': 'float64',
                'volume': 'float64'
            })
        candlesticks = df['time open close high low'.split()]
        volumes = df['time open close volume'.split()]
        boll = self.indicators.BOLL(20)
        upperband = boll['upperband']
        middleband = boll['middleband']
        lowerband = boll['lowerband']
        if not plots:
            # first time we create the plots
            global ax, ax2
            plots.append(fplt.candlestick_ochl(candlesticks))
            plots.append(fplt.volume_ocv(volumes, ax=ax2))
            plots.append(fplt.plot(upperband, legend="UPPERBAND"))
            plots.append(fplt.plot(middleband, legend="MIDDLEBAND"))
            plots.append(fplt.plot(lowerband, legend="LOWERBAND"))
        else:
            # every time after we just update the data sources on each plot
            plots[0].update_data(candlesticks)
            plots[1].update_data(volumes)
            plots[2].update_data(upperband)
            plots[3].update_data(middleband)
            plots[4].update_data(lowerband)
class Strategy:
    """布林强盗策略"""
    def __init__(self, instrument_id, time_frame, bollinger_lengths,
                 filter_length, start_asset):
        try:
            # 策略启动时控制台输出提示信息
            print("{} {} 布林强盗突破策略已启动!".format(get_localtime(),
                                              instrument_id))  # 程序启动时打印提示信息
            config.loads("config.json")  # 载入配置文件
            # 初始化
            self.instrument_id = instrument_id  # 合约ID
            self.time_frame = time_frame  # k线周期
            self.exchange = OKEXFUTURES(config.access_key, config.secret_key,
                                        config.passphrase,
                                        self.instrument_id)  # 交易所
            self.market = MARKET(self.exchange, self.instrument_id,
                                 self.time_frame)  # 行情
            self.position = POSITION(self.exchange, self.instrument_id,
                                     self.time_frame)  # 持仓
            self.indicators = INDICATORS(self.exchange, self.instrument_id,
                                         self.time_frame)  # 指标
            # 在第一次运行程序时,将初始资金、总盈亏等数据保存至数据库中
            self.database = "回测"  # 数据库,回测时必须为"回测"
            self.datasheet = self.instrument_id.split(
                "-")[0].lower() + "_" + time_frame  # 数据表
            if config.first_run == "true":
                storage.mysql_save_strategy_run_info(self.database,
                                                     self.datasheet,
                                                     get_localtime(), "none",
                                                     0, 0, 0, 0, "none", 0, 0,
                                                     0, start_asset)
            # 读取数据库中保存的总资金数据
            self.total_asset = storage.read_mysql_datas(
                0, self.database, self.datasheet, "总资金", ">")[-1][-1]
            self.total_profit = storage.read_mysql_datas(
                0, self.database, self.datasheet, "总资金", ">")[-1][-2]  # 策略总盈亏
            # 策略参数
            self.contract_value = self.market.contract_value()  # 合约面值
            self.counter = 0  # 计数器
            self.bollinger_lengths = bollinger_lengths  # 布林通道参数
            self.filter_length = filter_length  # 过滤器参数
            self.out_day = 50  # 自适应出场ma的初始值为50,开仓后赋值为布林通道参数的值
        except:
            logger.warning()

    def begin_trade(self, kline=None):
        try:  # 异常处理
            if self.indicators.CurrentBar(
                    kline=kline) < self.bollinger_lengths:  # 如果k线数据不够长就返回
                return

            timestamp = ts_to_datetime_str(utctime_str_to_ts(
                kline[-1]
                [0])) if kline else get_localtime()  # 非回测模式下时间戳就是当前本地时间

            if self.indicators.BarUpdate(kline=kline):
                self.counter = 0  # k线更新时还原计数器
                if self.out_day > 10:  # 计算MA的天数最小递减到10。如果达到10,则不再递减。
                    self.out_day -= 1  # 自适应出场ma的长度参数根据持仓周期递减,持有头寸的时间每多一天,计算MA的天数减1

            deviation = float(
                self.indicators.STDDEV(self.bollinger_lengths,
                                       nbdev=2,
                                       kline=kline)[-1])  # 标准差
            middleband = float(
                self.indicators.BOLL(self.bollinger_lengths,
                                     kline=kline)['middleband'][-1])  # 布林通道中轨
            upperband = float(middleband + deviation)  # 布林通道上轨
            lowerband = float(middleband - deviation)  # 布林通道下轨
            filter = float(
                self.market.close(-1, kline=kline) - self.market.close(
                    (self.filter_length * -1) - 1,
                    kline=kline))  # 过滤器:当日收盘价减去30日前的收盘价
            ma = float(self.indicators.MA(self.out_day,
                                          kline=kline)[-1])  # 自适应移动出场平均线

            # 策略主体
            # 若k线数据足够长,且满足过滤条件,且当根k线最高价大于等于布林通道上轨,买入开多。
            # 开仓处也设置计数器过滤,是为了防止没有启用交易助手的情况下挂单未成交,仓位为零时当根k线一直满足开仓条件,会重复挂单。
            if self.indicators.CurrentBar(
                    kline=kline
            ) >= self.bollinger_lengths and filter > 0 and self.market.high(
                    -1, kline=kline) > upperband and self.counter < 1:
                if self.position.amount() == 0:  # 若当前无持仓
                    price = upperband  # 开多价格为布林通道上轨的值
                    amount = round(self.total_asset / upperband /
                                   self.contract_value)  # 合约张数取整
                    info = self.exchange.buy(price,
                                             amount)  # 买入开多,并将返回的信息赋值给变量info
                    push(info)  # 推送信息
                    storage.mysql_save_strategy_run_info(
                        self.database, self.datasheet, timestamp, "买入开多",
                        price, amount, amount * price * self.contract_value,
                        price, "long", amount, 0, self.total_profit,
                        self.total_asset)  # 将信息保存至数据库
                    self.counter += 1  # 此策略是在盘中开仓,而在回测时,每根bar只会运行一次,每根bar上的价格不分时间先后,故此处开仓后计数器加1,也就是当根k线不平仓
                    # 因为实盘时每个ticker进来策略就会运行一次。注意回测和实盘策略运行机制的不同。
                    self.out_day = self.bollinger_lengths  # 开仓后赋值
            # 开空
            if self.indicators.CurrentBar(
                    kline=kline
            ) >= self.bollinger_lengths and filter < 0 and self.market.low(
                    -1, kline=kline) < lowerband and self.counter < 1:
                if self.position.amount() == 0:
                    price = lowerband
                    amount = round(self.total_asset / upperband /
                                   self.contract_value)
                    info = self.exchange.sellshort(price, amount)
                    push(info)
                    storage.mysql_save_strategy_run_info(
                        self.database, self.datasheet, timestamp, "卖出开空",
                        price, amount, amount * price * self.contract_value,
                        price, "short", amount, 0, self.total_profit,
                        self.total_asset)
                    self.counter += 1
                    self.out_day = self.bollinger_lengths  # 开仓后赋值
            # 如果当前持多,且当根k线最低价小于等于中轨值,触发保护性止损,就平多止损
            # 因为回测是一根k线上运行整个策略一次,所以要实现当根k线开仓后当根k线不平仓,需要将self.counter < 1的条件加在平仓的地方
            if self.position.direction() == "long" and self.market.low(
                    -1, kline=kline) < middleband and self.counter < 1:
                profit = self.position.coverlong_profit(
                    last=middleband)  # 此处计算平多利润时,传入最新价last为中轨值,也就是触发止损价格的那个值。
                self.total_profit += profit  # 计算经过本次盈亏后的总利润
                self.total_asset += profit  # 计算经过本次盈亏后的总资金
                price = middleband  # 平多价格为中轨值
                amount = self.position.amount()  # 平仓数量为当前持仓数量
                info = self.exchange.sell(price, amount)
                push(info)
                self.counter += 1
                storage.mysql_save_strategy_run_info(
                    self.database, self.datasheet, timestamp, "卖出止损", price,
                    amount, price * amount * self.contract_value, 0, "none", 0,
                    profit, self.total_profit, self.total_asset)
            if self.position.direction() == "short" and self.market.high(
                    -1, kline=kline) > middleband and self.counter < 1:
                profit = self.position.covershort_profit(last=middleband)
                self.total_profit += profit
                self.total_asset += profit
                price = middleband
                amount = self.position.amount()
                info = self.exchange.buytocover(price, amount)
                push(info)
                self.counter += 1
                storage.mysql_save_strategy_run_info(
                    self.database, self.datasheet, timestamp, "买入止损", price,
                    amount, amount * price * self.contract_value, 0, "none", 0,
                    profit, self.total_profit, self.total_asset)
            # 平多
            if self.position.direction(
            ) == "long" and upperband > ma > self.market.low(
                    -1, kline=kline) and self.counter < 1:
                profit = self.position.coverlong_profit(last=ma)
                self.total_profit += profit
                self.total_asset += profit
                price = ma  # 平仓价格为自适应出场均线的值
                amount = self.position.amount()
                info = self.exchange.sell(price, amount)
                push(info)
                self.counter += 1
                storage.mysql_save_strategy_run_info(
                    self.database, self.datasheet, timestamp, "卖出平多", price,
                    amount, price * amount * self.contract_value, 0, "none", 0,
                    profit, self.total_profit, self.total_asset)
            # 平空
            if self.position.direction(
            ) == "short" and lowerband < ma < self.market.high(
                    -1, kline=kline) and self.counter < 1:
                profit = self.position.covershort_profit(last=ma)
                self.total_profit += profit
                self.total_asset += profit
                price = ma
                amount = self.position.amount()
                info = self.exchange.buytocover(price, amount)
                push(info)
                self.counter += 1
                storage.mysql_save_strategy_run_info(
                    self.database, self.datasheet, timestamp, "买入平空", price,
                    amount, amount * price * self.contract_value, 0, "none", 0,
                    profit, self.total_profit, self.total_asset)
        except:
            logger.error()
Esempio n. 3
0
class SIGNALIZE:
    """实盘时根据从交易所获取的k线数据绘制k线图、成交量图及指标"""
    def __init__(self, platform, symbol, time_frame):

        self.__platform = platform
        self.__symbol = symbol
        self.__time_frame = time_frame
        self.__market = MARKET(self.__platform, self.__symbol,
                               self.__time_frame)

        # pull some data
        self.__indicators = INDICATORS(self.__platform, self.__symbol,
                                       self.__time_frame)
        self.__kline = platform.get_kline(self.__time_frame)
        self.__kline.reverse()

        # format it in pandas
        try:  # dataframe有7列的情况
            self.__df = pd.DataFrame(self.__kline,
                                     columns=[
                                         'time', 'open', 'high', 'low',
                                         'close', 'volume', 'currency_volume'
                                     ])
            self.__df = self.__df.astype({
                'time': 'datetime64[ns]',
                'open': 'float64',
                'close': 'float64',
                'high': 'float64',
                'low': 'float64',
                'volume': 'float64',
                'currency_volume': 'float64'
            })
        except:  # dataframe只有6列的情况,如okex的现货k线数据
            self.__df = pd.DataFrame(
                self.__kline,
                columns=['time', 'open', 'high', 'low', 'close', 'volume'])
            self.__df = self.__df.astype({
                'time': 'datetime64[ns]',
                'open': 'float64',
                'close': 'float64',
                'high': 'float64',
                'low': 'float64',
                'volume': 'float64'
            })

        # create three plot 创建三层图纸,第一层画k线,第二层画成交量,第三层画一些适宜于副图显示的指标
        fplt.foreground = '#FFFFFF'  # 前景色
        fplt.background = '#333333'  # 背景色
        fplt.odd_plot_background = '#333333'  # 第二层图纸的背景色
        fplt.cross_hair_color = "#FFFFFF"  # 准星的颜色
        self.__ax, self.__ax2, self.__ax3 = fplt.create_plot(symbol, rows=3)

        # plot candle sticks
        candles = self.__df[['time', 'open', 'close', 'high', 'low']]
        fplt.candlestick_ochl(candles, ax=self.__ax)

        # overlay volume on the plot
        volumes = self.__df[['time', 'open', 'close', 'volume']]
        fplt.volume_ocv(volumes, ax=self.__ax2)
        fplt.add_legend("VOLUME", self.__ax2)  # 增加"VOLUME"图例

    """
    plot indicators
    """

    def show(self):
        """最后必须调用此函数以显示图像"""
        fplt.show()

    def plot_last(self, color=None):
        """在图上画出最新成交价这根横线,便于观察"""
        last = self.__market.last()
        array = np.empty(len(self.__kline))
        array.fill(last)
        color = color if color is not None else "#CD7F32"  # 默认设置为红色
        fplt.plot(self.__df['time'],
                  array,
                  color=color,
                  ax=self.__ax,
                  legend="LAST {}".format(last))

    def plot_array(self, array, ax, legend, color=None):
        """
        绘制任意的数组成线性
        :param array: 传入一个数组
        :param ax: 加载在第几行的图上
        :param legend: 图例名称
        :param color: 颜色
        :return:
        """
        if ax == 1:
            ax = self.__ax
        elif ax == 2:
            ax = self.__ax2
        elif ax == 3:
            ax = self.__ax3
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        fplt.plot(self.__df['time'], array, color=color, ax=ax, legend=legend)

    def plot_atr(self, length, color=None):
        """
        在图上画出ATR
        :param length: ATR指标参数
        :param color: 线的颜色
        :return:
        """
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        fplt.plot(self.__df['time'],
                  self.__indicators.ATR(length),
                  color=color,
                  ax=self.__ax3,
                  legend='ATR({})'.format(length))

    def plot_boll(self, length, color1=None, color2=None, color3=None):
        """
        在图上画出布林通道的上轨、中轨、下轨
        :param length: BOLL指标参数
        :param upperband_color: 上轨颜色
        :param middleband_color: 中轨颜色
        :param lowerband_color: 下轨颜色
        :return:
        """
        color1 = color1 if color1 is not None else "#FF0000"  # 默认设置为红色
        color2 = color2 if color2 is not None else "#00FF00"  # 默认设置为绿色
        color3 = color3 if color3 is not None else "#0000FF"  # 默认设置为蓝色
        upperband_array = self.__indicators.BOLL(length)['upperband']
        middleband_array = self.__indicators.BOLL(length)["middleband"]
        lowerband_array = self.__indicators.BOLL(length)["lowerband"]
        fplt.plot(self.__df['time'],
                  upperband_array,
                  color=color1,
                  ax=self.__ax,
                  legend='BOLL({})-UPPERBAND'.format(length))
        fplt.plot(self.__df['time'],
                  middleband_array,
                  color=color2,
                  ax=self.__ax,
                  legend='BOLL({})-MIDDLEBAND'.format(length))
        fplt.plot(self.__df['time'],
                  lowerband_array,
                  color=color3,
                  ax=self.__ax,
                  legend='BOLL({})-LOWERBAND'.format(length))
        # 副图上也加载
        fplt.plot(self.__df['time'],
                  upperband_array,
                  color=color1,
                  ax=self.__ax3,
                  legend='BOLL({})-UPPERBAND'.format(length))
        fplt.plot(self.__df['time'],
                  middleband_array,
                  color=color2,
                  ax=self.__ax3,
                  legend='BOLL({})-MIDDLEBAND'.format(length))
        fplt.plot(self.__df['time'],
                  lowerband_array,
                  color=color3,
                  ax=self.__ax3,
                  legend='BOLL({})-LOWERBAND'.format(length))

    def plot_highest(self, length, color=None):
        """
        在图上画出最高价
        :param length: HIGHEST指标参数
        :param color: 线的颜色
        :return:
        """
        color = color if color is not None else "#FF0000"  # 默认设置红黑色
        fplt.plot(self.__df['time'],
                  self.__indicators.HIGHEST(length),
                  color=color,
                  ax=self.__ax,
                  legend='HIGHEST({})'.format(length))
        # 副图也加载
        fplt.plot(self.__df['time'],
                  self.__indicators.HIGHEST(length),
                  color=color,
                  ax=self.__ax3,
                  legend='HIGHEST({})'.format(length))

    def plot_ma(self, length, color=None):
        """
        在图上画出移动平均线
        :param length: 简单移动平均线参数
        :param color: 线的颜色
        :return:
        """
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        # 主图与副图加载指标
        fplt.plot(self.__df['time'],
                  self.__indicators.MA(length),
                  color=color,
                  ax=self.__ax,
                  legend='MA({})'.format(length))
        fplt.plot(self.__df['time'],
                  self.__indicators.MA(length),
                  color=color,
                  ax=self.__ax3,
                  legend='MA({})'.format(length))

    def plot_macd(self,
                  fastperiod,
                  slowperiod,
                  signalperiod,
                  color1=None,
                  color2=None,
                  color3=None):
        """
        在图上画出MACD指标
        :param fastperiod:
        :param slowperiod:
        :param signalperiod:
        :param color1:
        :param color2:
        :param color3:
        :return:
        """
        color1 = color1 if color1 is not None else "#FF0000"  # 默认设置为红色
        color2 = color2 if color2 is not None else "#00FF00"  # 默认设置为绿色
        color3 = color3 if color3 is not None else "#0000FF"  # 默认设置为蓝色
        dif = self.__indicators.MACD(fastperiod, slowperiod,
                                     signalperiod)['DIF']
        dea = self.__indicators.MACD(fastperiod, slowperiod,
                                     signalperiod)["DEA"]
        macd = self.__indicators.MACD(fastperiod, slowperiod,
                                      signalperiod)["MACD"]
        fplt.plot(self.__df['time'],
                  dif,
                  color=color1,
                  ax=self.__ax3,
                  legend='MACD({}, {}, {})-DIF'.format(fastperiod, slowperiod,
                                                       signalperiod))
        fplt.plot(self.__df['time'],
                  dea,
                  color=color2,
                  ax=self.__ax3,
                  legend='MACD({}, {}, {})-DEA'.format(fastperiod, slowperiod,
                                                       signalperiod))
        fplt.plot(self.__df['time'],
                  macd,
                  color=color3,
                  ax=self.__ax3,
                  legend='MACD({}, {}, {})-MACD'.format(
                      fastperiod, slowperiod, signalperiod))

    def plot_ema(self, length, color=None):
        """
        在图上画出EMA指标
        :param length:
        :param color:
        :return:
        """
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        fplt.plot(self.__df['time'],
                  self.__indicators.EMA(length),
                  color=color,
                  ax=self.__ax,
                  legend='EMA({})'.format(length))
        # 副图也加载
        fplt.plot(self.__df['time'],
                  self.__indicators.EMA(length),
                  color=color,
                  ax=self.__ax3,
                  legend='EMA({})'.format(length))

    def plot_kama(self, length, color=None):
        """在图上画出KAMA指标"""
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        fplt.plot(self.__df['time'],
                  self.__indicators.KAMA(length),
                  color=color,
                  ax=self.__ax,
                  legend='KAMA({})'.format(length))
        # 副图也加载
        fplt.plot(self.__df['time'],
                  self.__indicators.KAMA(length),
                  color=color,
                  ax=self.__ax3,
                  legend='KAMA({})'.format(length))

    def plot_kdj(self,
                 fastk_period,
                 slowk_period,
                 slowd_period,
                 color1=None,
                 color2=None):
        """
        在图上画出KDJ指标
        :param fastk_period:
        :param slowk_period:
        :param slowd_period:
        :param color1:
        :param color2:
        :param color3:
        :return:
        """
        color1 = color1 if color1 is not None else "#FF0000"  # 默认设置为红色
        color2 = color2 if color2 is not None else "#00FF00"  # 默认设置为绿色
        k = self.__indicators.KDJ(fastk_period, slowk_period,
                                  slowd_period)['k']
        d = self.__indicators.KDJ(fastk_period, slowk_period,
                                  slowd_period)["d"]
        # 仅副图加载
        fplt.plot(self.__df['time'],
                  k,
                  color=color1,
                  ax=self.__ax3,
                  legend='KDJ({}, {}, {})-K'.format(fastk_period, slowk_period,
                                                    slowd_period))
        fplt.plot(self.__df['time'],
                  d,
                  color=color2,
                  ax=self.__ax3,
                  legend='KDJ({}, {}, {})-D'.format(fastk_period, slowk_period,
                                                    slowd_period))

    def plot_lowest(self, length, color=None):
        """LOWEST"""
        color = color if color is not None else "#FF0000"  # 默认设置红黑色
        fplt.plot(self.__df['time'],
                  self.__indicators.LOWEST(length),
                  color=color,
                  ax=self.__ax,
                  legend='LOWEST({})'.format(length))
        # 副图也加载
        fplt.plot(self.__df['time'],
                  self.__indicators.LOWEST(length),
                  color=color,
                  ax=self.__ax3,
                  legend='LOWEST({})'.format(length))

    def plot_obv(self, color=None):
        """OBV"""
        color = color if color is not None else "#FF0000"  # 默认设置红黑色
        # 仅副图加载
        fplt.plot(self.__df['time'],
                  self.__indicators.OBV(),
                  color=color,
                  ax=self.__ax3,
                  legend='OBV')

    def plot_rsi(self, length, color=None):
        """RSI"""
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        # 仅副图加载
        fplt.plot(self.__df['time'],
                  self.__indicators.RSI(length),
                  color=color,
                  ax=self.__ax3,
                  legend='RSI({})'.format(length))

    def plot_roc(self, length, color=None):
        """ROC"""
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        # 仅副图加载
        fplt.plot(self.__df['time'],
                  self.__indicators.ROC(length),
                  color=color,
                  ax=self.__ax3,
                  legend='ROC({})'.format(length))

    def plot_stochrsi(self,
                      timeperiod,
                      fastk_period,
                      fastd_period,
                      color1=None,
                      color2=None):
        """STOCHRSI"""
        color1 = color1 if color1 is not None else "#FF0000"  # 默认设置为红色
        color2 = color2 if color2 is not None else "#00FF00"  # 默认设置为绿色
        stochrsi = self.__indicators.STOCHRSI(timeperiod, fastk_period,
                                              fastd_period)['stochrsi']
        fastk = self.__indicators.STOCHRSI(timeperiod, fastk_period,
                                           fastd_period)["fastk"]
        # 仅副图加载
        fplt.plot(self.__df['time'],
                  stochrsi,
                  color=color1,
                  ax=self.__ax3,
                  legend='STOCHRSI({}, {}, {})-STOCHRSI'.format(
                      timeperiod, fastk_period, fastd_period))
        fplt.plot(self.__df['time'],
                  fastk,
                  color=color2,
                  ax=self.__ax3,
                  legend='STOCHRSI({}, {}, {})-FASTK'.format(
                      timeperiod, fastk_period, fastd_period))

    def plot_sar(self, color=None):
        """
        在图上画出SAR
        :param length: SAR指标参数
        :param color: 线的颜色
        :return:
        """
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        # 主副图均加载
        fplt.plot(self.__df['time'],
                  self.__indicators.SAR(),
                  color=color,
                  ax=self.__ax,
                  legend='SAR')
        fplt.plot(self.__df['time'],
                  self.__indicators.SAR(),
                  color=color,
                  ax=self.__ax3,
                  legend='SAR')

    def plot_stddev(self, length, color=None):
        """STDDEV"""
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        # 仅副图加载
        fplt.plot(self.__df['time'],
                  self.__indicators.STDDEV(length),
                  color=color,
                  ax=self.__ax3,
                  legend='STDDEV({})'.format(length))

    def plot_trix(self, length, color=None):
        """STDDEV"""
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        # 仅副图加载
        fplt.plot(self.__df['time'],
                  self.__indicators.TRIX(length),
                  color=color,
                  ax=self.__ax3,
                  legend='TRIX({})'.format(length))

    def plot_volume(self, color=None):
        """VOLUME"""
        color = color if color is not None else "#FF0000"  # 默认设置为红色
        # 仅副图均加载
        fplt.plot(self.__df['time'],
                  self.__indicators.VOLUME(),
                  color=color,
                  ax=self.__ax3,
                  legend='VOLUME')