# -*- encoding:utf-8 -*-
"""上层回测图形可视化"""

from __future__ import print_function
from __future__ import absolute_import
from __future__ import division


import pandas as pd
from IPython.display import display
import ipywidgets as widgets

from ..UtilBu import ABuProgress
from ..WidgetBu.ABuWGBase import WidgetBase, show_msg_func, show_msg_toast_func
from ..WidgetBu.ABuWGBRunBase import WidgetRunTT
from ..WidgetBu.ABuWGBSymbol import WidgetSymbolChoice
from ..WidgetBu.ABuWGBFBase import BuyFactorWGManager
from ..WidgetBu.ABuWGSFBase import SellFactorWGManager
from ..WidgetBu.ABuWGPSBase import PickStockWGManager
from ..WidgetBu.ABuWGPosBase import PosWGManager

from ..CoreBu.ABu import run_loop_back
from ..CoreBu.ABuStore import store_abu_result_out_put
# noinspection PyUnresolvedReferences
from ..CoreBu.ABuFixes import filter
from ..MarketBu.ABuDataCheck import check_symbol_data_mode
from ..BetaBu import ABuAtrPosition, ABuPositionBase
from ..AlphaBu import ABuPickTimeExecute
from ..TradeBu.ABuBenchmark import AbuBenchmark
from ..TradeBu.ABuCapital import AbuCapital
from ..MetricsBu.ABuMetricsBase import AbuMetricsBase
from ..CoreBu.ABuStore import AbuResultTuple

__author__ = '阿布'
__weixin__ = 'abu_quant'


# noinspection PyProtectedMember
class WidgetRunLoopBack(WidgetBase):
    """基础界面可以化：初始资金，回测开始，结束周期，参考大盘等"""

    # noinspection PyProtectedMember
    def __init__(self):
        """构建回测需要的各个组件形成tab"""
        self.tt = WidgetRunTT()
        self.sc = WidgetSymbolChoice()
        self.bf = BuyFactorWGManager()

        self.sf = SellFactorWGManager()
        # 卖出策略管理注册买入策略接收改变
        self.sf.register(self.bf)

        self.ps = PickStockWGManager()
        # 选股策略管理注册买入策略接收改变
        self.ps.register(self.bf)

        self.pos = PosWGManager()
        # 资金管理注册买入策略接收改变
        self.pos.register(self.bf)

        sub_widget_tab = widgets.Tab()
        sub_widget_tab.children = [self.tt.widget, self.sc.widget, self.bf.widget, self.sf.widget, self.ps.widget,
                                   self.pos.widget]
        for ind, name in enumerate([u'基本', u'股池', u'买策', u'卖策', u'选股', u'资管']):
            sub_widget_tab.set_title(ind, name)

        self.run_loop_bt = widgets.Button(description=u'开始回测', layout=widgets.Layout(width='98%'),
                                          button_style='danger')
        self.run_loop_bt.on_click(self.run_loop_back)
        self.widget = widgets.VBox([sub_widget_tab, self.run_loop_bt])

    def _metrics_out_put(self, metrics, abu_result_tuple):
        """针对输出结果和界面中的设置进行输出操作"""
        if metrics is None:
            return

        if self.tt.metrics_mode.value == 0:
            metrics.plot_returns_cmp(only_show_returns=True)
        else:
            metrics.plot_order_returns_cmp(only_info=True)

        pd.options.display.max_rows = self.tt.out_put_display_max_rows.value
        pd.options.display.max_columns = self.tt.out_put_display_max_columns.value

        """
            options={u'只输出交易单：orders_pd': 0,
                     u'只输出行为单：action_pd': 1,
                     u'只输出资金单：capital_pd': 2,
                     u'同时输出交易单，行为单，资金单':3
        """
        if self.tt.metrics_out_put.value == 0 or self.tt.metrics_out_put.value == 3:
            show_msg_func(u'交易买卖详情单：')
            display(abu_result_tuple.orders_pd)
        if self.tt.metrics_out_put.value == 1 or self.tt.metrics_out_put.value == 3:
            show_msg_func(u'交易行为详情单：')
            display(abu_result_tuple.action_pd)
        if self.tt.metrics_out_put.value == 2 or self.tt.metrics_out_put.value == 3:
            show_msg_func(u'交易资金详细单：')
            display(abu_result_tuple.capital.capital_pd)
            show_msg_func(u'交易手续费详单：')
            display(abu_result_tuple.capital.commission.commission_df)

        if self.tt.save_out_put.value is True:
            # 本地保存各个交易单到文件
            store_abu_result_out_put(abu_result_tuple)

    # noinspection PyUnusedLocal
    def run_loop_back(self, bt):
        """运行回测所对应的button按钮"""
        # 清理之前的输出结果
        # ABuProgress.clear_output()

        base_run = self.tt
        # 初始资金
        cash = base_run.cash.value
        n_folds = 2
        start = None
        end = None
        if not base_run.run_years.disabled:
            # 如果使用年回测模式
            n_folds = base_run.run_years.value
        if not base_run.start.disabled:
            # 使用开始回测日期
            start = base_run.start.value
        if not base_run.end.disabled:
            # 使用结束回测日期
            end = base_run.end.value

        choice_symbols = self.sc.choice_symbols.options
        if choice_symbols is not None and len(choice_symbols) == 0:
            # 如果一个symbol都没有设置None， 将使用选择的市场进行全市场回测
            choice_symbols = None

        if not check_symbol_data_mode(choice_symbols):
            return

        # 买入策略构成序列
        buy_factors = list(self.bf.factor_dict.values())
        if len(buy_factors) == 0:
            msg = u'没有添加任何一个买入策略！'
            show_msg_toast_func(msg)
            return

        # 卖出策略可以一个也没有
        sell_factors = list(self.sf.factor_dict.values())

        pos_class_list = list(self.pos.factor_dict.values())
        if len(pos_class_list) == 1:
            # 资金仓位管理全局策略设置, [0]全局仓位管理策略只能是一个且是唯一
            ABuPositionBase.g_default_pos_class = pos_class_list[0]

        if choice_symbols is not None and len(choice_symbols) == 1:
            # 如果只有1支股票回测，直接使用这个股票做为做为对比基准
            benchmark = AbuBenchmark(choice_symbols[0])
            capital = AbuCapital(cash, benchmark)
            if len(pos_class_list) == 0:
                # 如果只有1支股票回测，且没有修改过资金管理设置，持仓比例调高
                ABuAtrPosition.g_atr_pos_base = 0.5
            # 就一只股票的情况下也不运行选股策略
            orders_pd, action_pd, _ = ABuPickTimeExecute.do_symbols_with_same_factors(choice_symbols,
                                                                                      benchmark,
                                                                                      buy_factors,
                                                                                      sell_factors,
                                                                                      capital, show=True)
            abu_result_tuple = AbuResultTuple(orders_pd, action_pd, capital, benchmark)
            metrics = AbuMetricsBase(orders_pd, action_pd, capital, benchmark)
        else:
            # 针对选股策略中需要choice_symbols的情况进行选股策略choice_symbols更新
            self.ps.seed_choice_symbol_update(choice_symbols)
            # 多只的情况下使用选股策略
            stock_picks = list(self.ps.factor_dict.values())
            if len(stock_picks) == 0:
                stock_picks = None

            # 多只股票使用run_loop_back
            abu_result_tuple, _ = run_loop_back(cash,
                                                buy_factors,
                                                sell_factors,
                                                stock_picks,
                                                choice_symbols=choice_symbols,
                                                start=start,
                                                end=end,
                                                n_folds=n_folds)
            if abu_result_tuple is None:
                return
            ABuProgress.clear_output()
            metrics = AbuMetricsBase(*abu_result_tuple)
        metrics.fit_metrics()
        self._metrics_out_put(metrics, abu_result_tuple)
