Exemplo n.º 1
0
    def _stat_avg_bar(self, df):
        """in out之间平均bar数"""
        bar_sum = 0
        # in out 总次数
        trade_sum = 0
        win = 0
        # TODO:放在metrics
        stack = []
        df['trading_datetime'] = pd.to_datetime(df['trading_datetime'])
        trade_list = df.sort_values('trading_datetime').to_dict(
            orient='records')
        frequency = Environment.get_instance().config.base.frequency * 60

        for t in trade_list:
            if not stack:
                stack.append(t)
            else:
                old_trade = stack[-1]
                old_side = old_trade['side']
                new_side = t['side']
                amount_cond = old_trade['amount'] == t['amount']
                if amount_cond and old_side == const.SIDE.BUY.name and new_side == const.SIDE.SELL.name:
                    old_trade = stack.pop()
                    diff_time = t['trading_datetime'] - old_trade[
                        'trading_datetime']
                    diff_bar = diff_time.seconds / frequency
                    trade_sum += 1
                    bar_sum += diff_bar
                    win += 1 if old_trade['price'] < t['price'] else 0
                # 还有其他判定条件
                else:
                    stack.append(t)
        if trade_sum == 0:
            return 0, len(stack), 0
        return round(bar_sum / trade_sum), len(stack), win / trade_sum
Exemplo n.º 2
0
 def annualized_returns(self):
     """
     年化收益率
     """
     current_date = Environment.get_instance().trading_dt.date()
     return self.unit_net_value**(DAYS_A_YEAR / float(
         (current_date - self.start_date.date()).days + 1)) - 1
Exemplo n.º 3
0
    def formatTime(self, record, datefmt=None):

        from quant.environment import Environment
        try:
            dt = Environment.get_instance().calendar_dt.strftime(datefmt)
        except Exception:
            dt = datetime.now().strftime(datefmt)
        return dt
Exemplo n.º 4
0
 def _on_bar(self, event):
     if len(self.positions) == 0:
         instrument = Environment.get_instance().get_instrument(
             self.benchmark)
         price = event.bar_dict[self.benchmark].close
         position = self.positions[self.benchmark]
         amount = self.total_cash / price
         position.amount = amount * (1 - instrument.fee)
         position.buy_price = price
         self.total_cash -= price * amount
Exemplo n.º 5
0
 def register_event(self):
     event_bus = Environment.get_instance().event_bus
     # 仓位控制
     event_bus.prepend_listener(EVENT.TRADE, self._on_trade)
     event_bus.add_listener(EVENT.ORDER_PENDING_NEW, self._on_order_pending_new)
     event_bus.add_listener(EVENT.ORDER_CANCELLATION_PASS, self._on_order_cancel)
     event_bus.add_listener(EVENT.ORDER_UNSOLICITED_UPDATE, self._on_order_cancel)
     event_bus.add_listener(EVENT.ORDER_CREATION_REJECT, self._on_order_cancel)
     # 结算
     event_bus.add_listener(EVENT.SETTLEMENT, self._on_settlement)
Exemplo n.º 6
0
 def __init__(self):
     self.order_id = None
     self.create_dt = None
     self.trade_dt = None
     self.symbol = None
     self.price = None
     self.amount = None
     self.fill_amount = None
     self.fee = None
     self.side = None
     self.type = None
     self.status = None
     self.message = None
     self.env = Environment.get_instance()
Exemplo n.º 7
0
 def create_trade(cls,
                  order_id,
                  symbol,
                  side,
                  price=0.,
                  frozen_price=0.,
                  amount=0.,
                  fee=0.):
     env = Environment.get_instance()
     trade = cls()
     trade.trade_id = next(env.id)
     trade.order_id = order_id
     trade.create_dt = env.calendar_dt
     trade.trade_dt = env.trading_dt
     trade.symbol = symbol
     trade.side = side
     trade.fee = fee
     trade.price = price
     trade.frozen_price = frozen_price
     trade.amount = amount
     return trade
Exemplo n.º 8
0
 def create_order(cls, symbol, price=0.,
                  amount=0., side=None, style=None):
     env = Environment.get_instance()
     symbol = symbol or env.config.base.symbol
     instrument = env.get_instrument(symbol)
     order = cls()
     order.order_id = next(env.id)
     order.create_dt = env.calendar_dt
     order.trade_dt = env.trading_dt
     order.symbol = symbol
     order.price = price
     order.amount = amount
     if order.amount < instrument.min_amount:
         raise ValueError('order amount should > min_amount')
     order.fill_amount = 0.
     order.fee = instrument.fee
     order.side = side
     order.type = style
     order.status = ORDER_STATUS.PENDING_NEW
     order.message = ""
     return order
Exemplo n.º 9
0
def run(config, kwargs):
    user_funcs = {
        'init': kwargs.init,
        'handle_bar': kwargs.handle_bar,
        'before_trading': kwargs.before_trading,
        'after_trading': kwargs.after_trading,
    }
    env = Environment(config)
    mod_handler = ModHandler(env)
    mod_handler.start()
    _adjust_env(env)
    try:
        context = Context()
        env.event_bus.publish_event(Event(EVENT.POST_SYSTEM_INIT))
        strategy = Strategy(env.event_bus, user_funcs, context)
        strategy.init()
        Executor(env).run()

        result = mod_handler.stop(const.EXIT_CODE.EXIT_SUCCESS)
        return result
    except Exception as e:
        sys_log.error(util.error_msg())
Exemplo n.º 10
0
    def portfolio(self):
        """
        投资组合

        =========================   =========================   ==============================================================================
        属性                         类型                        注释
        =========================   =========================   ==============================================================================
        accounts                    dict                        账户字典
        start_date                  datetime.datetime           策略投资组合的回测/实时模拟交易的开始日期
        units                       float                       份额
        unit_net_value              float                       净值
        daily_pnl                   float                       当日盈亏,当日盈亏的加总
        daily_returns               float                       投资组合每日收益率
        total_returns               float                       投资组合总收益率
        annualized_returns          float                       投资组合的年化收益率
        total_value                 float                       投资组合总权益
        positions                   dict                        一个包含所有仓位的字典,以symbol作为键,position对象作为值
        cash                        float                       总的可用资金
        market_value                float                       投资组合当前的市场价值,为子组合市场价值的加总
        =========================   =========================   ==============================================================================

        :property getter: :class:`~Portfolio`
        """
        return Environment.get_instance().portfolio
Exemplo n.º 11
0
 def last_price(self):
     """最新价"""
     return (self._last_price if self._last_price == self._last_price else
             Environment.get_instance().get_last_price(self.symbol))
Exemplo n.º 12
0
def generate_echart(result_dict=None, show_windows=True, savefile=None):
    summary = result_dict["summary"]
    portfolio = result_dict["portfolio"]
    benchmark_portfolio = result_dict.get("benchmark_portfolio")
    x_axis = portfolio.index

    # maxdrawdown
    portfolio_value = portfolio.unit_net_value * portfolio.start_cash
    xs = portfolio_value.values
    rt = portfolio.unit_net_value.values
    max_dd_end = np.argmax(np.maximum.accumulate(xs) / xs)
    if max_dd_end == 0:
        max_dd_end = len(xs) - 1
    max_dd_start = np.argmax(xs[:max_dd_end]) if max_dd_end > 0 else 0

    # maxdrawdown duration
    al_cum = np.maximum.accumulate(xs)
    a = np.unique(al_cum, return_counts=True)
    start_idx = np.argmax(a[1])
    m = a[0][start_idx]
    al_cum_array = np.where(al_cum == m)
    max_ddd_start_day = al_cum_array[0][0]
    max_ddd_end_day = al_cum_array[0][-1]

    max_dd_info = "MaxDD  {}~{}, {} days".format(
        x_axis[max_dd_start], x_axis[max_dd_end],
        (x_axis[max_dd_end] - x_axis[max_dd_start]).days)
    max_dd_info += "\nMaxDDD {}~{}, {} days".format(
        x_axis[max_ddd_start_day], x_axis[max_ddd_end_day],
        (x_axis[max_ddd_end_day] - x_axis[max_ddd_start_day]).days)

    red = "#aa4643"
    blue = "#4572a7"
    black = "#000000"

    font_size = 13
    value_font_size = 12
    label_height, value_height = 10, 40
    label_height2, value_height2 = 60, 90
    title = []
    fig_data = [
        ('15%', label_height, value_height, u"收益率",
         "{0:.3%}".format(summary["total_returns"]), red, black),
        ('15%', label_height2, value_height2, u"基准收益率",
         "{0:.3%}".format(summary.get("benchmark_total_returns",
                                      0)), blue, black),
        ('22%', label_height, value_height, u"年化收益率",
         "{0:.3%}".format(summary["annualized_returns"]), red, black),
        ('22%', label_height2, value_height2, u"基准年化收益率",
         "{0:.3%}".format(summary.get("benchmark_annualized_returns",
                                      0)), blue, black),
        ('32%', label_height, value_height, u"Alpha",
         "{0:.4f}".format(summary["alpha"]), black, black),
        ('32%', label_height2, value_height2, u"Volatility",
         "{0:.4f}".format(summary["volatility"]), black, black),
        ('40%', label_height, value_height, u"Beta",
         "{0:.4f}".format(summary["beta"]), black, black),
        ('40%', label_height2, value_height2, u"MaxDrawdown",
         "{0:.3%}".format(summary["max_drawdown"]), black, black),
        ('50%', label_height, value_height, u"Sharpe",
         "{0:.4f}".format(summary["sharpe"]), black, black),
        ('50%', label_height2, value_height2, u"Tracking Error",
         "{0:.4f}".format(summary["tracking_error"]), black, black),
        ('60%', label_height, value_height, u"Sortino",
         "{0:.4f}".format(summary["sortino"]), black, black),
        ('60%', label_height2, value_height2, u"Downside Risk",
         "{0:.4f}".format(summary["downside_risk"]), black, black),
        ('70%', label_height, value_height, u"Information Ratio",
         "{0:.4f}".format(summary["information_ratio"]), black, black),
    ]
    for x, y1, y2, label, value, label_color, value_color in fig_data:
        title.append(Text(x, y1, label, color=label_color, fontsize=font_size))
        title.append(
            Text(x, y2, value, color=value_color, fontsize=value_font_size))
    for x, y1, y2, label, value, label_color, value_color in [
        ('70%', label_height2, value_height2, "MaxDD/MaxDDD", max_dd_info,
         black, black)
    ]:
        title.append(Text(x, y1, label, color=label_color, fontsize=font_size))
        title.append(Text(x, y2, value, color=value_color, fontsize=8))

    page = Page()
    # title
    title_chart = Chart(title=title,
                        width=1000,
                        height=180,
                        show_xaxis=False,
                        show_yaxis=False)
    page.add(title_chart)

    # line
    line = Chart(title=Text(text='收益曲线'),
                 animation=False,
                 dataZoom=[
                     {
                         'type': 'slider',
                         'xAxisIndex': [0],
                     },
                     {
                         'type': 'inside',
                         'xAxisIndex': [0],
                     },
                 ])
    line.set_tooltip(**{
        'trigger': 'axis',
        'axisPointer': {
            'type': 'cross'
        },
    })
    line.set_xaxis(Axis(data=x_axis, type='category'))
    # plot strategy and benchmark
    line.line(label='strategy',
              data=portfolio["unit_net_value"] - 1.0,
              color=red)
    if benchmark_portfolio is not None:
        line.line(label='benchmark',
                  data=benchmark_portfolio["unit_net_value"] - 1.0,
                  color=blue)
    # plot MaxDD/MaxDDD
    line.line(label='MaxDrawdown',
              data=[
                  [x_axis[max_dd_end], rt[max_dd_end] - 1.0],
                  [x_axis[max_dd_start], rt[max_dd_start] - 1.0],
              ],
              color='green',
              smooth=False,
              fill=True,
              opacity=0.1)
    line.line(label='MaxDDD',
              data=[
                  [x_axis[max_ddd_start_day], rt[max_ddd_start_day] - 1.0],
                  [x_axis[max_ddd_end_day], rt[max_ddd_end_day] - 1.0],
              ],
              color='blue',
              smooth=False,
              fill=True,
              opacity=0.1)
    page.add(line)

    # kline
    upcolor, downcolor = '#52b986', '#ec4d5c'
    buycolor, sellcolor = '#018ffe', '#cc46ed'

    env = Environment.get_instance()
    k_bar = env.get_plot_bar()
    trade_mark, buy_trade, sell_trade, avg_bar, rest_trade, win_rate = \
        KLineMakePoint(mark_size=8).mark_point(result_dict['trades'])

    k_count = len(k_bar)
    buy_signal, sell_signal = env.buy_signal, env.sell_signal

    label_height, value_height = 10, 35
    label_height2, value_height2 = 70, 90
    profit = portfolio["unit_net_value"] - 1.0
    profit_loss_sum = np.sum(profit[profit < 0])
    title = []
    fig_data = [
        ('5%', label_height, value_height, u"buy", "{}|{} {:.2%}".format(
            buy_trade, buy_signal,
            buy_trade / buy_signal if buy_signal != 0 else 0), buycolor,
         black),
        ('5%', label_height2, value_height2, u"sell", "{}|{} {:.2%}".format(
            sell_trade, sell_signal,
            sell_trade / sell_signal if sell_signal != 0 else 0), sellcolor,
         black),
        ('17%', label_height, value_height, u"成交比例", "{}|{} {:.2%}".format(
            buy_trade + sell_trade, buy_signal + sell_signal,
            (buy_trade + sell_trade) / (buy_signal + sell_signal) if
            (buy_signal + sell_signal) != 0 else 0), black, black),
        ('17%', label_height2, value_height2, u"交易bar", "{}".format(k_count),
         black, black),
        ('30%', label_height, value_height, u"平均bar", "{}".format(avg_bar),
         black, black),
        ('30%', label_height2, value_height2, u"剩余交易", "{}".format(rest_trade),
         black, black),
        ('40%', label_height, value_height, u"资金利用率",
         "{:.2%}".format(1 - np.mean(portfolio['cash'] /
                                     portfolio['total_value'])), black, black),
        ('40%', label_height2, value_height2, u"盈亏比",
         "{:.2%}".format(-(np.sum(profit[profit > 0]) /
                           profit_loss_sum) if profit_loss_sum != 0 else 0),
         black, black),
        ('50%', label_height, value_height, u"平均win",
         "{:.4%}".format(np.mean(profit[profit > 0])), black, black),
        ('50%', label_height2, value_height2, u"平均loss",
         "{:.4%}".format(np.mean(profit[profit < 0])), black, black),
        ('60%', label_height, value_height, u"胜率", "{:.4%}".format(win_rate),
         black, black),
    ]
    for x, y1, y2, label, value, label_color, value_color in fig_data:
        title.append(Text(x, y1, label, color=label_color, fontsize=font_size))
        title.append(
            Text(x, y2, value, color=value_color, fontsize=value_font_size))

    title_chart = Chart(title=title,
                        height=150,
                        show_xaxis=False,
                        show_yaxis=False)
    page.add(title_chart)

    kline_chart = Chart(title=Text(text='K线交易'),
                        height=500,
                        animation=False,
                        show_legend=False,
                        dataZoom=[
                            {
                                'type': 'slider',
                                'xAxisIndex': [0, 1],
                                'start': 1,
                                'end': 35,
                                'top': '85%',
                            },
                            {
                                'type': 'inside',
                                'xAxisIndex': [0, 1],
                            },
                        ],
                        grid=[{
                            'left': '10%',
                            'right': '8%',
                            'height': '50%'
                        }, {
                            'left': '10%',
                            'right': '8%',
                            'bottom': '20%',
                            'height': '15%'
                        }],
                        axisPointer={'link': {
                            'xAxisIndex': 'all'
                        }},
                        visualMap={
                            'show':
                            False,
                            'seriesIndex':
                            1,
                            'pieces': [{
                                'value': 1,
                                'color': downcolor,
                            }, {
                                'value': -1,
                                'color': upcolor,
                            }]
                        })
    kline_chart.set_tooltip(**{
        'trigger': 'axis',
        'axisPointer': {
            'type': 'cross'
        },
    })
    kline_chart.set_xaxis([
        Axis(data=x_axis, type='category'),
        Axis(data=x_axis,
             type='category',
             axisTick={'show': False},
             axisLabel={'show': False},
             gridIndex=1)
    ])
    kline_chart.set_yaxis([
        Axis(scale=True),
        Axis(scale=True,
             axisLabel={'show': False},
             axisLine={'show': False},
             axisTick={'show': False},
             splitLine={'show': False},
             gridIndex=1)
    ])
    """k线"""
    kline_data = k_bar[['open', 'close', 'low', 'high']].copy().tolist()
    kline_chart.kline(label='k线',
                      data=kline_data,
                      upcolor=upcolor,
                      downcolor=downcolor,
                      markPoint=trade_mark)

    def color_volume(i, data):
        """交易量上色"""
        return [i, data['volume'], 1 if data['open'] > data['close'] else -1]

    ocv = k_bar[['open', 'close', 'volume']].copy()
    volume_data = [color_volume(i, data) for i, data in enumerate(ocv)]
    kline_chart.bar('volume',
                    data=volume_data,
                    xAxisIndex=1,
                    yAxisIndex=1,
                    itemStyle={})

    page.add(kline_chart)
    page.plot()
Exemplo n.º 13
0
 def __init__(self, cash, positions):
     super(BenchmarkAccount, self).__init__(cash, positions, True)
     self.benchmark = Environment.get_instance().config.base.benchmark
Exemplo n.º 14
0
 def register_event(self):
     event_bus = Environment.get_instance().event_bus
     event_bus.prepend_listener(EVENT.SETTLEMENT, self._on_settlement)
     event_bus.prepend_listener(EVENT.PRE_BAR, self._on_bar)
Exemplo n.º 15
0
 def __init__(self):
     config = Environment.get_instance().config
     self.slippage = getattr(config, 'slippage', 0)
     self.deciders = {
         ACCOUNT_TYPE.CRYPTO.name: CryptoSlippage(self.slippage),
     }
Exemplo n.º 16
0
 def now(self):
     """
     使用以上的方式就可以在handle_bar中拿到当前的bar的时间,比如day bar的话就是那天的时间,minute bar的话就是这一分钟的时间点。
     """
     return Environment.get_instance().calendar_dt
Exemplo n.º 17
0
 def init(self):
     if not self._init:
         return
     self._init(self._user_context)
     Environment.get_instance().event_bus.publish_event(
         Event(EVENT.POST_USER_INIT))
Exemplo n.º 18
0
 def symbol(self):
     return Environment.get_instance().config.base.symbol
Exemplo n.º 19
0
 def config(self):
     return Environment.get_instance().config
Exemplo n.º 20
0
 def register_event(self):
     event_bus = Environment.get_instance().event_bus
     event_bus.prepend_listener(EVENT.PRE_BEFORE_TRADING,
                                self._pre_before_trading)
Exemplo n.º 21
0
 def run_info(self):
     """
     :property getter: :class:`~RunInfo`
     """
     config = Environment.get_instance().config
     return RunInfo(config)