# -*- encoding:utf-8 -*-
"""
    买入择时示例因子：突破买入择时因子
"""

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

from .ABuFactorBuyBase import AbuFactorBuyBase, BuyCallMixin, BuyPutMixin

__author__ = '阿布'
__weixin__ = 'abu_quant'


# noinspection PyAttributeOutsideInit
class AbuFactorBuyBreak(AbuFactorBuyBase, BuyCallMixin):
    """示例正向突破买入择时类，混入BuyCallMixin，即向上突破触发买入event"""

    def _init_self(self, **kwargs):
        """kwargs中必须包含: 突破参数xd 比如20，30，40天...突破"""
        # 突破参数 xd， 比如20，30，40天...突破, 不要使用kwargs.pop('xd', 20), 明确需要参数xq
        self.xd = kwargs['xd']
        # 忽略连续创新高，比如买入后第二天又突破新高，忽略
        self.skip_days = 0
        # 在输出生成的orders_pd中显示的名字
        self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)

    def fit_day(self, today):
        """
        针对每一个交易日拟合买入交易策略，寻找向上突破买入机会
        :param today: 当前驱动的交易日金融时间序列数据
        :return:
        """

        # key是金融时间序列索引
        day_ind = int(today.key)
        # 忽略不符合买入的天（统计周期内前xd天及最后一天）
        if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
            return None

        # TODO: 如果子策略中使用skip_days频率高，加个装饰器，子类依据情况选择是否装饰
        if self.skip_days > 0:
            # 执行买入订单后的忽略，否则如果昨天突破了执行了买入，今天继续又比昨天高，难道继续买入吗
            self.skip_days -= 1
            return None

        # 今天的收盘价格达到xd天内最高价格则符合买入条件
        if today.close == self.kl_pd.close[day_ind - self.xd + 1:day_ind + 1].max():
            # 把突破新高参数赋值skip_days，这里也可以考虑make_buy_order确定是否买单成立，但是如果停盘太长时间等也不好
            self.skip_days = self.xd
            # 生成买入订单
            return self.make_buy_order(day_ind)
        return None


# noinspection PyAttributeOutsideInit
class AbuFactorBuyPutBreak(AbuFactorBuyBase, BuyPutMixin):
    """示例反向突破买入择时类，混入BuyPutMixin，即向下突破触发买入event，详情请查阅期货回测示例demo"""

    def _init_self(self, **kwargs):
        """kwargs中必须包含: 突破参数xd 比如20，30，40天...突破"""

        # 突破参数 xd， 比如20，30，40天...突破, 不要使用kwargs.pop('xd', 20), 明确需要参数xq
        self.xd = kwargs['xd']
        self.skip_days = 0
        self.factor_name = '{}:{}'.format(self.__class__.__name__, self.xd)

    def fit_day(self, today):
        """
        针对每一个交易日拟合买入交易策略，寻找向下突破买入机会
        :param today: 当前驱动的交易日金融时间序列数据
        :return:
        """
        day_ind = int(today.key)
        # 忽略不符合买入的天（统计周期内前xd天及最后一天）
        if day_ind < self.xd - 1 or day_ind >= self.kl_pd.shape[0] - 1:
            return None
        if self.skip_days > 0:
            # 执行买入订单后的忽略
            self.skip_days -= 1
            return None

        """
            与AbuFactorBuyBreak区别就是买向下突破的，即min()
        """
        if today.close == self.kl_pd.close[day_ind - self.xd + 1:day_ind + 1].min():
            self.skip_days = self.xd
            return self.make_buy_order(day_ind)
        return None
