SkillAgentSearch skills...

Quandomo2020

an event-driver quantative trading platform.

Install / Use

/learn @domodo2012/Quandomo2020
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

quandomo 框架概述 一、数据存贮与使用 1、数据存贮 从最基础的远程数据库中取数据,以相同的结构保存到本地(sqlite)数据库中。

2、数据使用 回测时,将数据从本地数据库中读取后,逐个时间戳形成市场事件推送入队列。 然后从队列中取数据,针对不同的事件类型,已注册的不同监控函数对应响应。

二、整体框架 1、后台事务在策略的父类中进行,具体的策略本身继承之后,重写 handle_bar、handle_order、handle_trade 等方法,实现具体的策略。 2、回测时,将数据从本地数据库中读出,逐个时间戳新建市场事件并推送入队列,之后从队列中取事件,不同的事件类型有已注册的不同监控函数响应,从而驱动策略运行。

三、例程

ExampleStrategy.py

-- coding: utf-8 --

Import … from … import ...

class TrialStrategyStock(StrategyBaseBacktestStock): def init(self, universe_limit): super(TrialStrategyStock, self).init(universe_limit)

def init_strategy(self, log_full_path: list, color_log=True, start_str='20180101', end_str='20200222'):  # 确定参数值
    self.gateway = 'ctp'
    self.run_mode = RunMode.BACKTESTING
    self.start = date_str_to_int(start_str)
    self.end = date_str_to_int(end_str)
    self.account = [{'name': 'acc0', 'equity': 200000}]
    self.benchmark = "000300.SH"
    # self.rights_adjustment = RightsAdjustment.NONE  # 只在画 K 线时有效,对策略运行无影响

    # 动态股票池(沪深300指数成分股)
    self.is_universe_dynamic = '000300.SH'

    # 固定股票池
    # self.is_universe_dynamic = False
    # self.universe = ['000562.SZ', '600710.SH', '600757.SH', '600761.SH']

    # 设置回测滑点
    self.set_slippage(symbol_type=Product.STOCK.value, slippage_type=Slippage.FIX, value=0.01)

    # 设置沪市交易成本
    self.set_commission(symbol_type=Product.STOCK_SH, tax=0.001, open_commission=0.0003,
                        close_commission=0.0005,
                        close_today_commission=0, min_commission=5)
    # 设置深市交易成本
    self.set_commission(symbol_type=Product.STOCK_SZ, tax=0.001, open_commission=0.0003,
                        close_commission=0.0003,
                        close_today_commission=0, min_commission=5)
    if not color_log:
        self.context.logger = Logger(log_full_path[0])
    else:
        self.context.logger = ColorLogger(log_full_path[0] + log_full_path[1])      # color log

def calc_position_size(self, account_available, symbol_price):
    psize = account_available / len(self.universe) * 0.9 / symbol_price
    psize = int(psize / 100) * 100
    return psize

def handle_bar(self, event_bar):
    self.context.logger.info("handle_bar() @ {0}".format(event_bar.dt))
    self.activate_trade_signal = False

    available_position_dict = self.context.bar_position_data_dict
    account_data = self.context.current_account_data

    current_date_int = date_str_to_int(event_bar.dt)
    cur_start_date = to_datetime(event_bar.dt) - Timedelta(days=60)
    cur_start_date_int = date_str_to_int(str(cur_start_date)[:10])

    # 循环处理旧持仓
    for pos_symbol in available_position_dict.keys():
        close_price = self.get_data.get_market_data(self.context.daily_data,
                                                    all_symbol_code=[pos_symbol],
                                                    field=["close"],
                                                    start=cur_start_date_int,
                                                    end=current_date_int)
        if len(close_price) > 0:
            # 指标计算
            ma5 = talib.MA(array(close_price), timeperiod=5)
            ma20 = talib.MA(array(close_price), timeperiod=20)

            if current_date_int in close_price.keys() and (not isnull(ma5[-1])) and (not isnull(ma20[-1])):
                if ma5[-1] < ma20[-1]:
                    if available_position_dict[pos_symbol].volume > 0 and available_position_dict[pos_symbol].direction == Direction.LONG:
                        self.activate_trade_signal = True
                        pos_abs = abs(available_position_dict[pos_symbol].volume)
                        comments = "限价卖出"
                        self.sell(event_bar.dt, self.account[0]['name'], pos_symbol,
                                  close_price.iloc[-1], pos_abs, False, comments)

                        self.context.logger.info(
                            "-- 资金账号 {3} 发出委托卖出 {0} {1} 股,委托价为 {2}".format(pos_symbol, pos_abs,
                                                                           close_price.iloc[-1],
                                                                           self.account[0]['name']))

    # 循环遍历股票池,看是否有新信号
    for symbol in self.universe:
        # 取当前股票的数据
        close_price = self.get_data.get_market_data(self.context.daily_data,
                                                    all_symbol_code=[symbol],
                                                    field=["close"],
                                                    start=cur_start_date_int,
                                                    end=current_date_int)
        # close_array = array(close_price)
        if len(close_price) > 0:
            # 指标计算
            ma5 = talib.MA(array(close_price), timeperiod=5)
            ma20 = talib.MA(array(close_price), timeperiod=20)

            # 数据有效时才判断
            if current_date_int in close_price.keys() and (not isnull(ma5[-1])) and (not isnull(ma20[-1])):
                # 如果5日均线突破20日均线,并且没有持仓,则买入这只股票100股,委托价为当前bar的收盘价
                if ma5[-1] > ma20[-1]:
                    # live模式下,此处需要更新一次持仓状态,这样判别持仓才准确
                    if symbol not in available_position_dict.keys():
                        self.activate_trade_signal = True
                        comments = "限价买入"
                        # psize = self.calc_position_size(account_data.available, close_price.iloc[-1])
                        psize = 300
                        if psize > 0:
                            self.buy(event_bar.dt, self.account[0]['name'], symbol, close_price.iloc[-1],
                                     psize, False, comments)

                            self.context.logger.info(
                                "-- 资金账号 {0} 发出委托买入 {1} {2} 股,委托价为 {3}".format(self.account[0]['name'],
                                                                               symbol, psize, close_price.iloc[-1]))

def handle_order(self, event_order):
    """针对委托单状态变动的响应"""
    self.context.logger.info('-- {0} 的委托单 {1} 当前状态是 {2}'.format(event_order.data.symbol,
                                                                event_order.data.order_id,
                                                                event_order.data.status))

def handle_trade(self, event_trade):
    """成交后立即添加止损止盈"""
    self.context.logger.info('-- {0} 的委托单 {1} 已成交,如有必要请立即添加止损止盈'.format(event_trade.data.symbol,
                                                                        event_trade.data.order_id))

if name == "main": output_path = 'D:/python projects/quandomo/doc/' log_name = '{0}.log'.format(strftime('%Y-%m-%d_%H%M%S')) is_color_log = True start_date = '20160104' # hs300 成分股数据开始于 20050408 end_date = '20190902' universe_limit = 5

# 测试运行完整个策略所需时间
time_test = Timer(True)
with time_test:
    trial_strategy = TrialStrategyStock(universe_limit)
    trial_strategy.init_strategy([output_path, log_name], is_color_log, start_date, end_date)
    trial_strategy.run_strategy()
    trial_strategy.strategy_analysis(output_path)  # 绩效分析
    trial_strategy.show_results(output_path)  # 运行结果展示

四、结果展示 1、log 文件(节选) [2020-11-02 12:33:17,289] [INFO]- handle_bar() @ 20170519 [2020-11-02 12:33:17,301] [INFO]- handle_bar() @ 20170522 [2020-11-02 12:33:17,312] [INFO]- handle_bar() @ 20170523 [2020-11-02 12:33:17,325] [INFO]- handle_bar() @ 20170524 [2020-11-02 12:33:17,338] [INFO]- -- 600000.SH 今日 20170525 除权除息,所持仓位量价相应变动 [2020-11-02 12:33:17,339] [INFO]- handle_bar() @ 20170525 [2020-11-02 12:33:17,343] [INFO]- -- 资金账号 acc0 发出委托卖出 600000.SH 389.99999999999994 股,委托价为 12.93 [2020-11-02 12:33:17,348] [INFO]- -- 资金账号 acc0 发出委托买入 000001.SZ 300 股,委托价为 9.1 [2020-11-02 12:33:17,352] [INFO]- -- 资金账号 acc0 发出委托买入 000002.SZ 300 股,委托价为 20.5 [2020-11-02 12:33:17,356] [INFO]- -- 600000.SH 的委托单 order_45210397 当前状态是 Status.NOT_TRADED [2020-11-02 12:33:17,356] [INFO]- -- 000001.SZ 的委托单 order_23461750 当前状态是 Status.NOT_TRADED [2020-11-02 12:33:17,357] [INFO]- -- 000002.SZ 的委托单 order_07982456 当前状态是 Status.NOT_TRADED [2020-11-02 12:33:17,359] [INFO]- -- 600000.SH 的委托单 order_45210397 无法成交,撤回重发 [2020-11-02 12:33:17,360] [INFO]- -- 600000.SH 的委托单 order_45210397 当前状态是 Status.WITHDRAW [2020-11-02 12:33:17,360] [INFO]- -- 资金账号 acc0 发出委托卖出 600000.SH 389.99999999999994 股,委托价为 12.81 [2020-11-02 12:33:17,361] [INFO]- -- 600000.SH 的委托单 order_78069125 当前状态是 Status.NOT_TRADED [2020-11-02 12:33:17,361] [INFO]- -- 600000.SH 的委托单 order_78069125 当前状态是 Status.ALL_TRADED [2020-11-02 12:33:17,362] [INFO]- -- 600000.SH 的委托单 order_78069125 于 20170526 成交,成交价为 12.92 [2020-11-02 12:33:17,363] [INFO]- -- 600000.SH 的委托单 order_78069125 已成交,如有必要请立即添加止损止盈 [2020-11-02 12:33:17,364] [INFO]- -- 000001.SZ 的委托单 order_23461750 当前状态是 Status.ALL_TRADED [2020-11-02 12:33:17,366] [INFO]- -- 000001.SZ 的委托单 order_23461750 于 20170526 成交,成交价为 9.09 [2020-11-02 12:33:17,366] [INFO]- -- 000001.SZ 的委托单 order_23461750 已成交,如有必要请立即添加止损止盈 [2020-11-02 12:33:17,367] [INFO]- -- 000002.SZ 的委托单 order_07982456 当前状态是 Status.ALL_TRADED [2020-11-02 12:33:17,368] [INFO]- -- 000002.SZ 的委托单 order_07982456 于 20170526 成交,成交价为 20.31 [2020-11-02 12:33:17,369] [INFO]- -- 000002.SZ 的委托单 order_07982456 已成交,如有必要请立即添加止损止盈 [2020-11-02 12:33:17,370] [INFO]- handle_bar() @ 20170526 [2020-11-02 12:33:17,388] [INFO]- handle_bar() @ 20170531 [2020-1

View on GitHub
GitHub Stars8
CategoryDevelopment
Updated1mo ago
Forks3

Languages

Python

Security Score

70/100

Audited on Feb 26, 2026

No findings