Exemple #1
0
class OnePiece(object):

    env = Environment()

    def __init__(self):
        self.market_maker = MarketMaker()
        self.order_checker = PendingOrderChecker()
        self.cur_event = None
        self.env.logger = logging.getLogger("OnePy")

    def sunny(self, summary=True):
        """主循环,OnePy的核心"""
        self._initialize_trading_system()

        while True:
            try:
                self.cur_event = self.env.event_bus.get()
            except queue.Empty:
                try:
                    self.market_maker.update_market()
                    self.order_checker.run()
                except BacktestFinished:
                    self.output.summary() if summary else None

                    break
            else:
                self._run_event_loop()

    def _run_event_loop(self):
        for element in self.env.event_loop:
            if self._event_is_executed(**element):
                break

    def _event_is_executed(self, if_event, then_event, module_dict):
        if self.cur_event.event_type == if_event:
            [value.run() for value in module_dict.values()]
            self.env.event_bus.put(Event(then_event)) if then_event else None

            return True

    def _initialize_trading_system(self):
        self.env.refresh()
        OnePyEnvBase.env = self.env
        self.env.event_loop = EVENT_LOOP
        self.market_maker.initialize()

        if self.env.recorder:
            self.env.recorder.initialize()

    @property
    def output(self):
        return OutPut()

    def show_log(self, file=False):
        if file:
            LoggerFactory("OnePy").logger
        logging.basicConfig(level=logging.INFO)
def test_frequency_generate():
    # 若不指定 frequency, 是否会产生新的 frequency
    set_easy_context()
    StockRecorder()
    reader = CSVReader(data_path='./', file_name=TICKER, ticker=TICKER)
    MarketMaker._initialize_feeds()
    MarketMaker._initialize_calendar()

    cleaner = SMA(rolling_window=10, buffer_day=20)
    cleaner.initialize_buffer_data(TICKER, buffer_day=20)
    assert cleaner.frequency == FREQUENCY
def func_test_update_cleaner(frequency):
    set_easy_context()
    StockRecorder()
    reader = CSVReader(data_path='./', file_name=TICKER, ticker=TICKER)
    cleaner = SMA(rolling_window=10, buffer_day=10, frequency=frequency)
    cleaner2 = SMA(rolling_window=10, buffer_day=1, frequency=frequency)
    env = reader.env

    # 初始化
    MarketMaker._initialize_feeds()
    MarketMaker._initialize_calendar()
    MarketMaker._initialize_cleaners()  # 以sys_date初始化

    # 以 sys_date 来进行初始化数据,因为一开始 sys_date 会比 fromdate 向前一步
    # 测试开始回测时 buffer 数据最新一条是否为 Start 前一根 bar 的数据。
    key = f'{TICKER}_{frequency}'
    assert arrow.get(cleaner.data[key]['date'][-1]) <= arrow.get(env.sys_date)

    # sys_date和cleaner中的数据都更新到和fromdate同步
    MarketMaker.calendar.update_calendar()
    MarketMaker._update_bar()
    cleaner.run()

    if INSTRUMENT == 'A_Shares':  # 测试buffer_day是否会自动变化
        assert cleaner2.buffer_day == 5

    if cleaner.frequency == env.sys_frequency:
        cur_bar = env.feeds[TICKER]
    else:
        cur_bar = env.cleaners_feeds[key + '_' + cleaner.name]

    # cleaner run之后日期一切正常
    latest_date = cleaner.data[key]['date'][-1]
    assert latest_date == cur_bar.date, f'{latest_date} != {cur_bar.date}'

    # 测试更新后是否成功
    env.execute_on_close_or_next_open = 'open'
    env.cur_suspended_tickers.clear()
    MarketMaker.calendar.update_calendar()
    MarketMaker._update_bar()

    cleaner.run()
    latest_date = cleaner.data[key]['date'][-1]
    assert latest_date == cur_bar.date, f'{latest_date} != {cur_bar.date}'
    assert cleaner.data[key]['open'][-1] == cur_bar.current_ohlc['open']
    assert cleaner.data[key]['high'][-1] == cur_bar.current_ohlc['high']
    assert cleaner.data[key]['low'][-1] == cur_bar.current_ohlc['low']
    assert cleaner.data[key]['close'][-1] == cur_bar.current_ohlc['close']
    assert cleaner.data[key]['volume'][-1] == cur_bar.current_ohlc['volume']
Exemple #4
0
    def _save_cleaners_feeds(self, ticker: str):
        key = f'{ticker}_{self.frequency}_{self.name}'

        value = MarketMaker.get_bar(ticker, self.frequency)

        if value.initialize(7):
            self.env.cleaners_feeds.update({key: value})
def func_test_reader(reader: op.ReaderBase):
    def test_load(start, end, iter_data):
        first_date = next(iter_data)['date']
        assert isinstance(first_date, str), "it should be iterable"

        if FREQUENCY == 'H1':
            shift_num = 1 / 24
        elif FREQUENCY == 'D':
            shift_num = 1
        next_date = shift_date(first_date, shift_num)
        assert next(iter_data)['date'] == next_date
        last_date = [i for i in iter_data][-1]['date']
        assert arrow.get(last_date) <= arrow.get(
            end), f"{last_date} can't more than {END}"

    StockRecorder()
    go = op.OnePiece()
    go.set_date(START, END, FREQUENCY, INSTRUMENT)

    test_iter_data = reader.load(START, END, FREQUENCY)
    test_load(START, END, test_iter_data)

    NEW_START = shift_date(START, -9)
    NEW_END = shift_date(NEW_START, 10)
    test_iter_data = reader.load_by_cleaner(NEW_START, NEW_END, FREQUENCY)
    test_load(NEW_START, NEW_END, test_iter_data)

    # 获取bar
    bars = MarketMaker.get_bar(TICKER, FREQUENCY)
    assert isinstance(bars, BarBase)
    assert reader in reader.env.readers.values()
def test_different_frequency():
    set_easy_context()
    StockRecorder()
    reader = CSVReader(data_path='./', file_name=TICKER, ticker=TICKER)
    MarketMaker._initialize_feeds()
    MarketMaker._initialize_calendar()

    cleaner = SMA(rolling_window=10, buffer_day=20, frequency=FREQUENCY)
    cleaner.initialize_buffer_data(TICKER, buffer_day=20)
    key = f'{TICKER}_{FREQUENCY}'

    # 测试不同 frequency 是否会新建 cleaner feed
    assert key + '_' + cleaner.name in reader.env.cleaners_feeds

    # 低 frequency 的 cleaners feed 中 bar 的更新不超过系统 bar 时间
    MarketMaker.env.cur_suspended_tickers.clear()
    MarketMaker.calendar.update_calendar()
    MarketMaker._update_bar()
    cleaner.run()
    cleaner_latest_date = cleaner.data[key]['date'][-1]
    bar_latest_date = cleaner.env.feeds[TICKER].date
    assert arrow.get(cleaner_latest_date) == arrow.get(bar_latest_date)
    assert arrow.get(cleaner_latest_date) <= arrow.get(cleaner.env.sys_date)
    func_test_update_cleaner(FREQUENCY)
    func_test_update_cleaner('H1')
Exemple #7
0
 def _pre_initialize_trading_system(self):
     self.event_loop = EVENT_LOOP
     self.market_maker = MarketMaker()
     self.pending_order_checker = PendingOrderChecker()
Exemple #8
0
class OnePiece(OnePyEnvBase):
    def __init__(self):
        # 内置模块
        self.market_maker: MarketMaker = None
        self.pending_order_checker: PendingOrderChecker = None
        self.event_loop: list = None

        # 其他模块
        self.optimizer = Optimizer()
        self.forward_analysis = ForwardAnalysis()

    def _pre_initialize_trading_system(self):
        self.event_loop = EVENT_LOOP
        self.market_maker = MarketMaker()
        self.pending_order_checker = PendingOrderChecker()

    def initialize_trading_system(self):  # 清空内存,便于参数优化
        self._pre_initialize_trading_system()
        self.env.initialize_env()
        self.market_maker.initialize()
        self.env.recorder.initialize()

    def sunny(self, summary: bool = True, show_process: bool = False):
        """主循环,OnePy的核心"""
        self.initialize_trading_system()

        while True:
            try:
                if self.env.event_engine.is_empty():
                    self.market_maker.update_market()
                    self.pending_order_checker.run()

                    if show_process:
                        self._show_process()
                else:
                    cur_event = self.env.event_engine.get()
                    self._run_event_loop(cur_event)

            except BacktestFinished:
                if summary:
                    print("\n")
                    self.output.summary()

                break

    def _run_event_loop(self, cur_event):
        for element in self.event_loop:
            if self._event_is_executed(cur_event, **element):
                break

    def _event_is_executed(self, cur_event, if_event: EVENT, then_event: EVENT,
                           module_dict: dict) -> bool:

        if cur_event is None:
            return True

        elif cur_event == if_event:
            [value.run() for value in module_dict.values()]
            self.env.event_engine.put(then_event)

            return True
        else:
            return False

    def _show_process(self):
        fromdate = arrow.get(self.env.fromdate)
        todate = arrow.get(self.env.todate)
        curdate = arrow.get(self.env.sys_date)
        total_days = (todate - fromdate).days
        finished_days = (curdate - fromdate).days
        show_process(finished_days, total_days)

    def set_date(self, fromdate: str, todate: str, frequency: str,
                 instrument: str):
        """
        Instrument: A_shares, Forex
        Frequency:
                (S5, S10, S30, M1, M2, M4, M5) <- BAD Interval
                M10, M15, M30, H1, H2, H3, H4, H6, H8, H12
        """
        self.env.instrument = instrument
        self.env.fromdate = fromdate
        self.env.todate = todate
        self.env.sys_frequency = frequency

    def set_forex_live_trading(self, frequency: str):
        """
        Frequency:
                (S5, S10, S30, M1, M2, M4, M5) <- BAD Interval
                M10, M15, M30, H1, H2, H3, H4, H6, H8, H12
        """
        fromdate = arrow.utcnow().format("YYYY-MM-DD HH:mm:ss")
        self.set_date(fromdate, None, frequency, "Forex")
        self.env.sys_date = fromdate
        self.env.is_live_trading = True

    def show_today_signals(self):
        """
        能够显示当天的最新信号,但是会导致回测结果不准确。
        """
        self.env.is_show_today_signals = True

    @classmethod
    def show_log(cls, file=False, no_console=False):
        if file:
            LoggerFactory("OnePy")

        if no_console:
            logging.getLogger("OnePy").propagate = False
        logging.basicConfig(level=logging.INFO)

    @classmethod
    def set_recursion_limit(cls, limit: int = 2000):
        """
        突破递归次数限制,有时候信号太多会导致撮合引擎递归太多次而假死
        """
        sys.setrecursionlimit(limit)

    def save_original_signal(self):
        self.env.is_save_original = True

    @property
    def output(self) -> OutPut:
        return OutPut()
Exemple #9
0
 def __init__(self):
     self.market_maker = MarketMaker()
     self.order_checker = PendingOrderChecker()
     self.cur_event = None
     self.env.logger = logging.getLogger("OnePy")