示例#1
0
class ExecuteUnit(object):
    """ 策略执行的物理单元,支持多个组合同时运行。
    """
    def __init__(self,
                 pcontracts,
                 dt_start="1980-1-1",
                 dt_end="2100-1-1",
                 n=None,
                 spec_date={}):  # 'symbol':[,]
        """
        Args:
            pcontracts (list): list of pcontracts(string)

            dt_start (datetime/str): start time of all pcontracts

            dt_end (datetime/str): end time of all pcontracts

            n (int): last n bars

            spec_date (dict): time range for specific pcontracts
        """
        self.finished_data = []
        pcontracts = map(lambda x: x.upper(), pcontracts)
        self.pcontracts = pcontracts
        self._combs = []
        self._data_manager = DataManager()
        # str(PContract): DataWrapper
        if settings['source'] == 'csv':
            self.pcontracts = self._parse_pcontracts(self.pcontracts)
        self._default_pcontract = self.pcontracts[0]
        self._all_data, self._max_window = self._load_data(
            self.pcontracts, dt_start, dt_end, n, spec_date)
        self.context = Context(self._all_data, self._max_window)

    def _init_strategies(self):
        for pcon, dcontext in self._all_data.iteritems():
            # switch context
            self.context.switch_to_pcontract(pcon)
            for i, combination in enumerate(self._combs):
                for j, s in enumerate(combination):
                    self.context.switch_to_strategy(i, j)
                    s.on_init(self.context)

    @deprecated
    def _parse_pcontracts(self, pcontracts):
        # @TODO test
        code2strpcon, exch_period2strpcon = \
            self._data_manager.get_code2strpcon()
        rst = []
        for strpcon in pcontracts:
            strpcon = strpcon.upper()
            code = strpcon.split('.')[0]
            if code == "*":
                if strpcon == "*":  # '*'
                    for key, value in exch_period2strpcon.iteritems():
                        rst += value
                else:
                    # "*.xxx"
                    # "*.xxx_period"
                    k = strpcon.split('.')[1]
                    for key, value in exch_period2strpcon.iteritems():
                        if '-' in k:
                            if k == key:
                                rst += value
                        elif k == key.split('-')[0]:
                            rst += value
            else:
                try:
                    pcons = code2strpcon[code]
                except IndexError:
                    raise IndexError  # 本地不含该文件
                else:
                    for pcon in pcons:
                        if '-' in strpcon:
                            # "xxx.xxx_xxx.xxx"
                            if strpcon == pcon:
                                rst.append(pcon)
                        elif '.' in strpcon:
                            # "xxx.xxx"
                            if strpcon == pcon.split('-')[0]:
                                rst.append(pcon)
                        elif strpcon == pcon.split('.')[0]:
                            # "xxx"
                            rst.append(pcon)
                        #if strpcon in pcon:
                        #rst.append(strpcon)
        return rst

    def add_comb(self, comb, settings):
        """ 添加策略组合组合

        Args:
            comb (list): 一个策略组合
        """
        self._combs.append(comb)
        num_strategy = len(comb)
        if 'capital' not in settings:
            settings['capital'] = 1000000.0  # 默认资金
            logger.info('BackTesting with default capital 1000000.0.')

        assert (settings['capital'] > 0)
        if num_strategy == 1:
            settings['ratio'] = [1]
        elif num_strategy > 1 and 'ratio' not in settings:
            settings['ratio'] = [1.0 / num_strategy] * num_strategy
        assert ('ratio' in settings)
        assert (len(settings['ratio']) == num_strategy)
        assert (sum(settings['ratio']) - 1.0 < 0.000001)
        assert (num_strategy >= 1)
        ctxs = []
        for i, s in enumerate(comb):
            iset = {}
            if settings:
                iset = {'capital': settings['capital'] * settings['ratio'][i]}
                # logger.debug(iset)
            ctxs.append(StrategyContext(s.name, iset))
        self.context.add_strategy_context(ctxs)
        return blotter.Profile(ctxs, self._all_data, self.pcontracts[0],
                               len(self._combs) - 1)

    def run(self):
        # @TODO max_window 可用来显示回测进度
        # 初始化策略自定义时间序列变量
        logger.info("runing strategies...")
        self._init_strategies()
        pbar = ProgressBar().start()
        # todo 对单策略优化
        has_next = True
        # 遍历每个数据轮, 次数为数据的最大长度
        for pcon, data in self._all_data.iteritems():
            self.context.switch_to_pcontract(pcon)
            self.context.rolling_forward()
        while True:
            self.context.on_bar = False
            # 遍历数据轮的所有合约
            for pcon, data in self._all_data.iteritems():
                self.context.switch_to_pcontract(pcon)
                if self.context.time_aligned():
                    self.context.update_system_vars()
                    # 组合遍历
                    for i, combination in enumerate(self._combs):
                        # 策略遍历
                        for j, s in enumerate(combination):
                            self.context.switch_to_strategy(i, j)
                            self.context.update_user_vars()
                            s.on_symbol(self.context)
            # 确保单合约回测的默认值
            self.context.switch_to_pcontract(self._default_pcontract)
            self.context.on_bar = True
            # 遍历组合策略每轮数据的最后处理
            tick_test = settings['tick_test']
            for i, combination in enumerate(self._combs):
                # print self.context.ctx_datetime, "--"
                for j, s in enumerate(combination):
                    self.context.switch_to_strategy(i, j)
                    # 确保交易状态是基于开盘时间的。
                    self.context.process_trading_events(at_baropen=True)
                    s.on_bar(self.context)
                    if not tick_test:
                        # 保证有可能在当根Bar成交
                        self.context.process_trading_events(at_baropen=False)
            # print self.context.ctx_datetime
            self.context.ctx_datetime = datetime(2100, 1, 1)
            self.context.ctx_curbar += 1
            if self.context.ctx_curbar <= self._max_window:
                pbar.update(self.context.ctx_curbar * 100.0 / self._max_window)
            #
            toremove = []
            for pcon, data in self._all_data.iteritems():
                self.context.switch_to_pcontract(pcon)
                has_next = self.context.rolling_forward()
                if not has_next:
                    toremove.append(pcon)
            if toremove:
                for key in toremove:
                    del self._all_data[key]
                if len(self._all_data) == 0:
                    # 策略退出后的处理
                    for i, combination in enumerate(self._combs):
                        for j, s in enumerate(combination):
                            self.context.switch_to_strategy(i, j)
                            s.on_exit(self.context)
                    return
        pbar.finish()

    def _load_data(self, strpcons, dt_start, dt_end, n, spec_date):
        all_data = OrderedDict()
        max_window = -1
        logger.info("loading data...")
        pbar = ProgressBar().start()
        pcontracts = [PContract.from_string(s) for s in strpcons]
        pcontracts = sorted(pcontracts, reverse=True)
        for i, pcon in enumerate(pcontracts):
            strpcon = str(pcon)
            if strpcon in spec_date:
                dt_start = spec_date[strpcon][0]
                dt_end = spec_date[strpcon][1]
            assert (dt_start < dt_end)
            if n:
                wrapper = self._data_manager.get_last_bars(strpcon, n)
            else:
                wrapper = self._data_manager.get_bars(strpcon, dt_start,
                                                      dt_end)
            if len(wrapper) == 0:
                continue
            all_data[strpcon] = DataContext(wrapper)
            max_window = max(max_window, len(wrapper))
            pbar.update(i * 100.0 / len(strpcons))
            # progressbar.log('')
        if n:
            assert (max_window <= n)
        pbar.finish()
        if len(all_data) == 0:
            assert (False)
            # @TODO raise
        return all_data, max_window
示例#2
0
class ExecuteUnit(object):
    """ 策略执行的物理单元,支持多个组合同时运行。
    """
    def __init__(self,
                 pcontracts,
                 dt_start="1980-1-1",
                 dt_end="2100-1-1",
                 n=None,
                 spec_date={}):  # 'symbol':[,]
        """
        Args:
            pcontracts (list): list of pcontracts(string)

            dt_start (datetime/str): start time of all pcontracts

            dt_end (datetime/str): end time of all pcontracts

            n (int): last n bars

            spec_date (dict): time range for specific pcontracts
        """
        self.finished_data = []
        pcontracts = map(lambda x: x.upper(), pcontracts)
        self.pcontracts = pcontracts
        self._combs = []
        self._data_manager = DataManager()
        # str(PContract): DataWrapper
        if settings['source'] == 'csv':
            self.pcontracts = self._parse_pcontracts(self.pcontracts)
        self._default_pcontract = self.pcontracts[0]
        self._all_data, self._max_window = self._load_data(self.pcontracts,
                                                           dt_start,
                                                           dt_end,
                                                           n,
                                                           spec_date)
        self.context = Context(self._all_data, self._max_window)

    def _init_strategies(self):
        for pcon, dcontext in self._all_data.iteritems():
            # switch context
            self.context.switch_to_pcontract(pcon)
            for i, combination in enumerate(self._combs):
                for j, s in enumerate(combination):
                    self.context.switch_to_strategy(i, j)
                    s.on_init(self.context)

    @deprecated
    def _parse_pcontracts(self, pcontracts):
        # @TODO test
        code2strpcon, exch_period2strpcon = \
            self._data_manager.get_code2strpcon()
        rst = []
        for strpcon in pcontracts:
            strpcon = strpcon.upper()
            code = strpcon.split('.')[0]
            if code == "*":
                if strpcon == "*":  # '*'
                    for key, value in exch_period2strpcon.iteritems():
                        rst += value
                else:
                    # "*.xxx"
                    # "*.xxx_period"
                    k = strpcon.split('.')[1]
                    for key, value in exch_period2strpcon.iteritems():
                        if '-' in k:
                            if k == key:
                                rst += value
                        elif k == key.split('-')[0]:
                                rst += value
            else:
                try:
                    pcons = code2strpcon[code]
                except IndexError:
                    raise IndexError  # 本地不含该文件
                else:
                    for pcon in pcons:
                        if '-' in strpcon:
                            # "xxx.xxx_xxx.xxx"
                            if strpcon == pcon:
                                rst.append(pcon)
                        elif '.' in strpcon:
                            # "xxx.xxx"
                            if strpcon == pcon.split('-')[0]:
                                rst.append(pcon)
                        elif strpcon == pcon.split('.')[0]:
                            # "xxx"
                            rst.append(pcon)
                        #if strpcon in pcon:
                            #rst.append(strpcon)
        return rst

    def add_comb(self, comb, settings):
        """ 添加策略组合组合

        Args:
            comb (list): 一个策略组合
        """
        self._combs.append(comb)
        num_strategy = len(comb)
        if 'capital' not in settings:
            settings['capital'] = 1000000.0  # 默认资金
            logger.info('BackTesting with default capital 1000000.0.')

        assert (settings['capital'] > 0)
        if num_strategy == 1:
            settings['ratio'] = [1]
        elif num_strategy > 1 and 'ratio' not in settings:
            settings['ratio'] = [1.0/num_strategy] * num_strategy
        assert('ratio' in settings)
        assert(len(settings['ratio']) == num_strategy)
        assert(sum(settings['ratio']) - 1.0 < 0.000001)
        assert(num_strategy >= 1)
        ctxs = []
        for i, s in enumerate(comb):
            iset = {}
            if settings:
                iset = {'capital': settings['capital'] * settings['ratio'][i]}
                # logger.debug(iset)
            ctxs.append(StrategyContext(s.name, iset))
        self.context.add_strategy_context(ctxs)
        return blotter.Profile(ctxs,
                               self._all_data,
                               self.pcontracts[0],
                               len(self._combs)-1)

    def run(self):
        # @TODO max_window 可用来显示回测进度
        # 初始化策略自定义时间序列变量
        logger.info("runing strategies...")
        self._init_strategies()
        pbar = ProgressBar().start()
        # todo 对单策略优化
        has_next = True
        # 遍历每个数据轮, 次数为数据的最大长度
        for pcon, data in self._all_data.iteritems():
            self.context.switch_to_pcontract(pcon)
            self.context.rolling_forward()
        while True:
            self.context.on_bar = False
            # 遍历数据轮的所有合约
            for pcon, data in self._all_data.iteritems():
                self.context.switch_to_pcontract(pcon)
                if self.context.time_aligned():
                    self.context.update_system_vars()
                    # 组合遍历
                    for i, combination in enumerate(self._combs):
                        # 策略遍历
                        for j, s in enumerate(combination):
                            self.context.switch_to_strategy(i, j)
                            self.context.update_user_vars()
                            s.on_symbol(self.context)
            # 确保单合约回测的默认值
            self.context.switch_to_pcontract(self._default_pcontract)
            self.context.on_bar = True
            # 遍历组合策略每轮数据的最后处理
            tick_test = settings['tick_test']
            for i, combination in enumerate(self._combs):
                # print self.context.ctx_datetime, "--"
                for j, s in enumerate(combination):
                    self.context.switch_to_strategy(i, j)
                    # 确保交易状态是基于开盘时间的。
                    self.context.process_trading_events(at_baropen=True)
                    s.on_bar(self.context)
                    if not tick_test:
                        # 保证有可能在当根Bar成交
                        self.context.process_trading_events(at_baropen=False)
            # print self.context.ctx_datetime
            self.context.ctx_datetime = datetime(2100, 1, 1)
            self.context.ctx_curbar += 1
            if self.context.ctx_curbar <= self._max_window:
                pbar.update(self.context.ctx_curbar*100.0/self._max_window)
            #
            toremove = []
            for pcon, data in self._all_data.iteritems():
                self.context.switch_to_pcontract(pcon)
                has_next = self.context.rolling_forward()
                if not has_next:
                    toremove.append(pcon)
            if toremove:
                for key in toremove:
                    del self._all_data[key]
                if len(self._all_data) == 0:
                    # 策略退出后的处理
                    for i, combination in enumerate(self._combs):
                        for j, s in enumerate(combination):
                            self.context.switch_to_strategy(i, j)
                            s.on_exit(self.context)
                    return
        pbar.finish()

    def _load_data(self, strpcons, dt_start, dt_end, n, spec_date):
        all_data = OrderedDict()
        max_window = -1
        logger.info("loading data...")
        pbar = ProgressBar().start()
        pcontracts = [PContract.from_string(s) for s in strpcons]
        pcontracts = sorted(pcontracts, reverse=True)
        for i, pcon in enumerate(pcontracts):
            strpcon = str(pcon)
            if strpcon in spec_date:
                dt_start = spec_date[strpcon][0]
                dt_end = spec_date[strpcon][1]
            assert(dt_start < dt_end)
            if n:
                wrapper = self._data_manager.get_last_bars(strpcon, n)
            else:
                wrapper = self._data_manager.get_bars(strpcon, dt_start, dt_end)
            if len(wrapper) == 0:
                continue
            all_data[strpcon] = DataContext(wrapper)
            max_window = max(max_window, len(wrapper))
            pbar.update(i*100.0/len(strpcons))
            # progressbar.log('')
        if n:
            assert(max_window <= n)
        pbar.finish()
        if len(all_data) == 0:
            assert(False)
            # @TODO raise
        return all_data, max_window