From a5cea20c51e091b8e7711cb5b3243bbb0426ed84 Mon Sep 17 00:00:00 2001 From: 1122455801 Date: Fri, 17 May 2019 14:57:53 +0800 Subject: [PATCH 1/4] Create algo_trader.md --- docs/algo_trader.md | 321 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 docs/algo_trader.md diff --git a/docs/algo_trader.md b/docs/algo_trader.md new file mode 100644 index 00000000..c411c451 --- /dev/null +++ b/docs/algo_trader.md @@ -0,0 +1,321 @@ +# 算法交易 +算法交易一般用于把巨型单子拆分成一个个小单,能够有效降低交易成本,冲击成本等。 + +  + +## 模块构成 + +算法交易模块主要由4部分构成,如下图: + +- engine:定义了算法引擎,其中包括:引擎初始化、保存/移除/加载算法配置、启动算法、停止算法、订阅行情、挂撤单等。 +- template:定义了交易算法模板,具体的算法示例,如冰山算法,都需要继承于该模板。 +- algos:官方提供的交易算法示例,包括:冰山算法、狙击手算法、时间加权平均算法、条件委托、最优限价。 +- ui:基于PyQt5的GUI图形应用。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/algo_trader_document.png) + +  + +## 基本操作 + +在VN Trader的菜单栏中点击“功能”—>“算法交易”即可打开如图算法交易模块窗口,如下图。 + +算法交易模块有2部分构成: +- 委托交易,用于启动算法交易; +- 数据监控,用于监控算法交易执行情况,并且能够手动停止算法。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/algo_trader_all_section.png) + +  + +### 委托交易 + +下面以时间加权平均算法为例,具体介绍如下图委托交易功能选项。 +- 算法:目前提供了5种交易算法:时间加权平均算法、冰山算法、狙击手算法、条件委托、最优限价; +- 本地代码:vt_symbol格式,如AAPL.SMART, 用于算法交易组建订阅行情和委托交易; +- 方向:做多或者做空; +- 价格:委托下单的价格; +- 数量:委托的总数量,需要拆分成小单进行交易; +- 执行时间:运行改算法交易的总时间,以秒为单位; +- 每轮间隔:每隔一段时间(秒)进行委托下单操作; +- 启动算法:设置好算法配置后,用于立刻执行算法交易。 + +所以,该算法执行的任务如下:通过时间加权平均算法,买入10000股AAPL(美股),执行价格为180美金,执行时间为600秒,间隔为6秒;即每隔6秒钟,当买一价少于等于180时,以180的价格买入100股AAPL,买入操作分割成100次。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/trading_section.png) + +交易配置可以保存在json文件,这样每次打开算法交易模块就不用重复输入配置。其操作是在“算法名称”选项输入该算法设置命名,然后点击下方"保存设置”按钮。保存的json文件在C:\Users\Administrator\\.vntrader文件夹的algo_trading_setting.json中,如图。 +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/setting.png) + +委托交易界面最下方的“全部停止”按钮用于一键停止所有执行中的算法交易。 + +  + +### 数据监控 + +数据监控由4个部分构成。 + +- 活动组件:显示正在运行的算法交易,包括:算法名称、参数、状态。最右边的“停止”按钮用于手动停止执行中的算法。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/action.png) + +  + +- 历史委托组件:显示已完成的算法交易,同样包括:算法名称、参数、状态。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/final.png) + +  + +- 日志组件:显示启动、停止、完成算法的相关日志信息。在打开算法交易模块后,会进行初始化,故日志上会首先显示“算法交易引擎启动”和“算法配置载入成功”。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/log_section.png) + +  + +- 配置组件:用于载入algo_trading_setting.json的配置信息,并且以图形化界面显示出来。 +用户可以点击“使用”按钮立刻读取配置信息,并显示在委托交易界面上,点击“启动算法”即可开始进行交易; +用户也可以点击“移除”按钮来移除该算法配置,同步更新到json文件内。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/setting_section.png) + +  + +## 算法示例 + +### 时间加权平均算法 + +- 将委托数量平均分布在某个时间区域内; +- 每隔一段时间用指定的价格挂出买单(或者卖单)。 +- 买入情况:买一价低于目标价格时,发出委托,委托数量在剩余委托量与委托分割量中取最小值。 +- 卖出情况:卖一价高于目标价格时,发出委托,委托数量在剩余委托量与委托分割量中取最小值。 + +``` + def on_timer(self): + """""" + self.timer_count += 1 + self.total_count += 1 + self.put_variables_event() + + if self.total_count >= self.time: + self.write_log("执行时间已结束,停止算法") + self.stop() + return + + if self.timer_count < self.interval: + return + self.timer_count = 0 + + tick = self.get_tick(self.vt_symbol) + if not tick: + return + + self.cancel_all() + + left_volume = self.volume - self.traded + order_volume = min(self.order_volume, left_volume) + + if self.direction == Direction.LONG: + if tick.ask_price_1 <= self.price: + self.buy(self.vt_symbol, self.price, + order_volume, offset=self.offset) + else: + if tick.bid_price_1 >= self.price: + self.sell(self.vt_symbol, self.price, + order_volume, offset=self.offset) +``` + +  + +### 冰山算法 + +- 在某个价位挂单,但是只挂一部分,直到全部成交。 +- 买入情况:先检查撤单:最新Tick卖一价低于目标价格,执行撤单;若无活动委托,发出委托:委托数量在剩余委托量与挂出委托量中取最小值。 +- 卖出情况:先检查撤单:最新Tick买一价高于目标价格,执行撤单;若无活动委托,发出委托:委托数量在剩余委托量与挂出委托量中取最小值。 + +``` + def on_timer(self): + """""" + self.timer_count += 1 + + if self.timer_count < self.interval: + self.put_variables_event() + return + + self.timer_count = 0 + + contract = self.get_contract(self.vt_symbol) + if not contract: + return + + # If order already finished, just send new order + if not self.vt_orderid: + order_volume = self.volume - self.traded + order_volume = min(order_volume, self.display_volume) + + if self.direction == Direction.LONG: + self.vt_orderid = self.buy( + self.vt_symbol, + self.price, + order_volume, + offset=self.offset + ) + else: + self.vt_orderid = self.sell( + self.vt_symbol, + self.price, + order_volume, + offset=self.offset + ) + # Otherwise check for cancel + else: + if self.direction == Direction.LONG: + if self.last_tick.ask_price_1 <= self.price: + self.cancel_order(self.vt_orderid) + self.vt_orderid = "" + self.write_log(u"最新Tick卖一价,低于买入委托价格,之前委托可能丢失,强制撤单") + else: + if self.last_tick.bid_price_1 >= self.price: + self.cancel_order(self.vt_orderid) + self.vt_orderid = "" + self.write_log(u"最新Tick买一价,高于卖出委托价格,之前委托可能丢失,强制撤单") + + self.put_variables_event() +``` + +  + +### 狙击手算法 + +- 监控最新tick推送的行情,发现好的价格立刻报价成交。 +- 买入情况:最新Tick卖一价低于目标价格时,发出委托,委托数量在剩余委托量与卖一量中取最小值。 +- 卖出情况:最新Tick买一价高于目标价格时,发出委托,委托数量在剩余委托量与买一量中取最小值。 + +``` + def on_tick(self, tick: TickData): + """""" + if self.vt_orderid: + self.cancel_all() + return + + if self.direction == Direction.LONG: + if tick.ask_price_1 <= self.price: + order_volume = self.volume - self.traded + order_volume = min(order_volume, tick.ask_volume_1) + + self.vt_orderid = self.buy( + self.vt_symbol, + self.price, + order_volume, + offset=self.offset + ) + else: + if tick.bid_price_1 >= self.price: + order_volume = self.volume - self.traded + order_volume = min(order_volume, tick.bid_volume_1) + + self.vt_orderid = self.sell( + self.vt_symbol, + self.price, + order_volume, + offset=self.offset + ) + + self.put_variables_event() +``` + +  + +### 条件委托算法 + +- 监控最新tick推送的行情,发现行情突破立刻报价成交。 +- 买入情况:Tick最新价高于目标价格时,发出委托,委托价为目标价格加上超价。 +- 卖出情况:Tick最新价低于目标价格时,发出委托,委托价为目标价格减去超价。 + +``` + def on_tick(self, tick: TickData): + """""" + if self.vt_orderid: + return + + if self.direction == Direction.LONG: + if tick.last_price >= self.stop_price: + price = self.stop_price + self.price_add + + if tick.limit_up: + price = min(price, tick.limit_up) + + self.vt_orderid = self.buy( + self.vt_symbol, + price, + self.volume, + offset=self.offset + ) + self.write_log(f"停止单已触发,代码:{self.vt_symbol},方向:{self.direction}, 价格:{self.stop_price},数量:{self.volume},开平:{self.offset}") + + else: + if tick.last_price <= self.stop_price: + price = self.stop_price - self.price_add + + if tick.limit_down: + price = max(price, tick.limit_down) + + self.vt_orderid = self.buy( + self.vt_symbol, + price, + self.volume, + offset=self.offset + ) + self.write_log(f"停止单已触发,代码:{self.vt_symbol},方向:{self.direction}, 价格:{self.stop_price},数量:{self.volume},开平:{self.offset}") + + self.put_variables_event() +``` + +  + +### 最优限价算法 + +- 监控最新tick推送的行情,发现好的价格立刻报价成交。 +- 买入情况:先检查撤单:最新Tick买一价不等于目标价格时,执行撤单;若无活动委托,发出委托:委托价格为最新Tick买一价,委托数量为剩余委托量。 +- 卖出情况:先检查撤单:最新Tick买一价不等于目标价格时,执行撤单;若无活动委托,发出委托:委托价格为最新Tick卖一价,委托数量为剩余委托量。 + +``` + def on_tick(self, tick: TickData): + """""" + self.last_tick = tick + + if self.direction == Direction.LONG: + if not self.vt_orderid: + self.buy_best_limit() + elif self.order_price != self.last_tick.bid_price_1: + self.cancel_all() + else: + if not self.vt_orderid: + self.sell_best_limit() + elif self.order_price != self.last_tick.ask_price_1: + self.cancel_all() + + self.put_variables_event() + + def buy_best_limit(self): + """""" + order_volume = self.volume - self.traded + self.order_price = self.last_tick.bid_price_1 + self.vt_orderid = self.buy( + self.vt_symbol, + self.order_price, + order_volume, + offset=self.offset + ) + + def sell_best_limit(self): + """""" + order_volume = self.volume - self.traded + self.order_price = self.last_tick.ask_price_1 + self.vt_orderid = self.sell( + self.vt_symbol, + self.order_price, + order_volume, + offset=self.offset + ) +``` \ No newline at end of file From 2a91d6b9b65e941a2979955e2fb80fffe1963427 Mon Sep 17 00:00:00 2001 From: 1122455801 Date: Fri, 17 May 2019 14:57:58 +0800 Subject: [PATCH 2/4] Create data_recoder.md --- docs/data_recoder.md | 271 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 docs/data_recoder.md diff --git a/docs/data_recoder.md b/docs/data_recoder.md new file mode 100644 index 00000000..8c3bc076 --- /dev/null +++ b/docs/data_recoder.md @@ -0,0 +1,271 @@ +# 行情记录 +行情记录模块用于实时行情的收录: +- 连接上接口后并且启动行情记录模块; +- 通过本地合约(vt_symbol)添加记录任务; +- 后台会自动调用行情API接口的suscribe()函数自动订阅行情; +- 行情信息通过database_manager模块的save_bar_data()函数/save_tick_data()函数载入到数据库中。 + +注意:目前vnpy支持的数据库为SQLite/ MySQL/ PostgreSQL/ MongoDB。若用户使用MongoDB,则行情记录数据直接载入到MongoDB中。 + +  + + + +## 加载启动 +进入VN Trader后,首先登陆接口,如连接CTP;然后在菜单栏中点击“功能”->"行情记录“后,会弹出行情记录窗口,如图。 +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/data_recoder/datarecoder.png) + +此时行情记录模块的启动状态为True,会启动while循环,可以添加任务实现实时行情记录。 +``` + def start(self): + """""" + self.active = True + self.thread.start() + + def run(self): + """""" + while self.active: + try: + task = self.queue.get(timeout=1) + task_type, data = task + + if task_type == "tick": + database_manager.save_tick_data([data]) + elif task_type == "bar": + database_manager.save_bar_data([data]) + + except Empty: + continue +``` + +  + +## 开始收录 + +- 在“本地代码”选择输入需要订阅的行情,如rb1905.SHFE; +- 然后点击后边“K线记录”或者“Tick记录”中的“添加”选项,会把记录特定品种任务添加到data_recorder_setting.json上,并且显示到“K线记录列表”或者“Tick记录列表”中,如图。 +- 通过queue.put()与queue.get()异步完成收录行情信息任务。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/data_recoder/start.png) + +  + +下面介绍行情收录的具体原理:若无合约记录的历史,用户需要先添加行情记录任务,如连接CTP接口后记录rb1905.SHFE的tick数据,然后调用add_tick_recording()函数执行下面工作: +1) 先创建tick_recordings字典; +2) 调用接口的suscribe()函数订阅行情; +3 )保存该tick_recordings字典到json文件上; +4) 推送行情记录事件。 + +``` + def add_tick_recording(self, vt_symbol: str): + """""" + if vt_symbol in self.tick_recordings: + self.write_log(f"已在Tick记录列表中:{vt_symbol}") + return + + contract = self.main_engine.get_contract(vt_symbol) + if not contract: + self.write_log(f"找不到合约:{vt_symbol}") + return + + self.tick_recordings[vt_symbol] = {} + "symbol": contract.symbol, + "exchange": contract.exchange.value, + "gateway_name": contract.gateway_name + } + + self.subscribe(contract) + self.save_setting() + self.put_event() + + self.write_log(f"添加Tick记录成功:{vt_symbol}") +``` + +下面对add_tick_recording()函数里面调用的子函数进行扩展: + +### 订阅行情 + +调用main_engine的suscribe()函数来订阅行情,需要填入的信息为symbol、exchange、gateway_name +``` + def subscribe(self, contract: ContractData): + """""" + req = SubscribeRequest( + symbol=contract.symbol, + exchange=contract.exchange + ) + self.main_engine.subscribe(req, contract.gateway_name) +``` + +  + +### 将订阅信息保存到json文件 + +- 主要把tick_recordings或者bar_recordings通过save_json()函数保存到C:\Users\Administrator\\.vntrader文件夹内的data_recorder_setting.json上。 +- 该json文件用于存放行情记录的任务,当每次启动行情模块后,会调用load_setting()函数来得到tick_recordings和bar_recordings字典,进而开始记录的任务。 +``` +setting_filename = "data_recorder_setting.json" + def save_setting(self): + """""" + setting = { + "tick": self.tick_recordings, + "bar": self.bar_recordings + } + save_json(self.setting_filename, setting) + + def load_setting(self): + """""" + setting = load_json(self.setting_filename) + self.tick_recordings = setting.get("tick", {}) + self.bar_recordings = setting.get("bar", {}) +``` + +  + +### 推送行情记录事件 + +- 创建行情记录列表tick_symbols和bar_symbols,并且缓存在data字典里; +- 创建evnte对象,其类型是EVENT_RECORDER_UPDATE, 内容是data字典; +- 调用event_engine的put()函数推送event事件。 + +``` + def put_event(self): + """""" + tick_symbols = list(self.tick_recordings.keys()) + tick_symbols.sort() + + bar_symbols = list(self.bar_recordings.keys()) + bar_symbols.sort() + + data = { + "tick": tick_symbols, + "bar": bar_symbols + } + + event = Event( + EVENT_RECORDER_UPDATE, + data + ) + self.event_engine.put(event) +``` + +  + +### 注册行情记录事件 + +register_event()函数分别注册2种事件:EVENT_CONTRACT、EVENT_TICK +- EVENT_CONTRACT事件,调用的是process_contract_event()函数: 从tick_recordings和bar_recordings字典获取需要订阅的合约品种;然后使用subscribe()函数进行订阅行情。 +- EVENT_TICK事件,调用的是process_tick_event()函数:从tick_recordings和bar_recordings字典获取需要订阅的合约品种;然后使用record_tick()和record_bar()函数,把行情记录任务推送到queue队列中等待执行。 + +``` + def register_event(self): + """""" + self.event_engine.register(EVENT_TICK, self.process_tick_event) + self.event_engine.register(EVENT_CONTRACT, self.process_contract_event) + + def process_tick_event(self, event: Event): + """""" + tick = event.data + + if tick.vt_symbol in self.tick_recordings: + self.record_tick(tick) + + if tick.vt_symbol in self.bar_recordings: + bg = self.get_bar_generator(tick.vt_symbol) + bg.update_tick(tick) + + def process_contract_event(self, event: Event): + """""" + contract = event.data + vt_symbol = contract.vt_symbol + + if (vt_symbol in self.tick_recordings or vt_symbol in self.bar_recordings): + self.subscribe(contract) + + def record_tick(self, tick: TickData): + """""" + task = ("tick", copy(tick)) + self.queue.put(task) + + def record_bar(self, bar: BarData): + """""" + task = ("bar", copy(bar)) + self.queue.put(task) + + def get_bar_generator(self, vt_symbol: str): + """""" + bg = self.bar_generators.get(vt_symbol, None) + + if not bg: + bg = BarGenerator(self.record_bar) + self.bar_generators[vt_symbol] = bg + + return bg +``` + +  + +### 执行记录行情任务 + +在while循环中,从queue队列读取任务,调用save_tick_data()或者save_bar_data()函数来记录数据,并且载入到数据库中。 +``` + def run(self): + """""" + while self.active: + try: + task = self.queue.get(timeout=1) + task_type, data = task + + if task_type == "tick": + database_manager.save_tick_data([data]) + elif task_type == "bar": + database_manager.save_bar_data([data]) + + except Empty: + continue +``` + +  + + + + +## 移除记录 + +移除记录操作:输入需要移除合约品种的本地代码,如rb1905.SHFE。该本地代码必须在“Tick记录列表” 或者“K线记录列表”中。若要移除Tick记录,只需在”Tick记录“那一栏上点击”移除“按钮即可。 + +下面展示代码运作原理: + +- 从tick_recordings字典移除vt_symbol +- 调用save_setting()函数保存json配置文件 +- 推送最新的tick_recordings字典来继续记录行情,原来移除合约品种不再记录。 +``` + def remove_tick_recording(self, vt_symbol: str): + """""" + if vt_symbol not in self.tick_recordings: + self.write_log(f"不在Tick记录列表中:{vt_symbol}") + return + + self.tick_recordings.pop(vt_symbol) + self.save_setting() + self.put_event() + + self.write_log(f"移除Tick记录成功:{vt_symbol}") +``` + +  + +## 停止记录 + +停止记录操作:只需手动关闭行情记录模块窗口就停止记录行情。 + +- 记录行情状态改为False, 停止while循环; +- 调用join()函数关掉线程。 + +``` + def close(self): + """""" + self.active = False + + if self.thread.isAlive(): + self.thread.join() +``` \ No newline at end of file From f12b38afbcdb186c5e3e4d0936a1319976e36863 Mon Sep 17 00:00:00 2001 From: 1122455801 Date: Fri, 17 May 2019 14:58:02 +0800 Subject: [PATCH 3/4] Delete datarecoder.md --- docs/datarecoder.md | 271 -------------------------------------------- 1 file changed, 271 deletions(-) delete mode 100644 docs/datarecoder.md diff --git a/docs/datarecoder.md b/docs/datarecoder.md deleted file mode 100644 index 8c3bc076..00000000 --- a/docs/datarecoder.md +++ /dev/null @@ -1,271 +0,0 @@ -# 行情记录 -行情记录模块用于实时行情的收录: -- 连接上接口后并且启动行情记录模块; -- 通过本地合约(vt_symbol)添加记录任务; -- 后台会自动调用行情API接口的suscribe()函数自动订阅行情; -- 行情信息通过database_manager模块的save_bar_data()函数/save_tick_data()函数载入到数据库中。 - -注意:目前vnpy支持的数据库为SQLite/ MySQL/ PostgreSQL/ MongoDB。若用户使用MongoDB,则行情记录数据直接载入到MongoDB中。 - -  - - - -## 加载启动 -进入VN Trader后,首先登陆接口,如连接CTP;然后在菜单栏中点击“功能”->"行情记录“后,会弹出行情记录窗口,如图。 -![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/data_recoder/datarecoder.png) - -此时行情记录模块的启动状态为True,会启动while循环,可以添加任务实现实时行情记录。 -``` - def start(self): - """""" - self.active = True - self.thread.start() - - def run(self): - """""" - while self.active: - try: - task = self.queue.get(timeout=1) - task_type, data = task - - if task_type == "tick": - database_manager.save_tick_data([data]) - elif task_type == "bar": - database_manager.save_bar_data([data]) - - except Empty: - continue -``` - -  - -## 开始收录 - -- 在“本地代码”选择输入需要订阅的行情,如rb1905.SHFE; -- 然后点击后边“K线记录”或者“Tick记录”中的“添加”选项,会把记录特定品种任务添加到data_recorder_setting.json上,并且显示到“K线记录列表”或者“Tick记录列表”中,如图。 -- 通过queue.put()与queue.get()异步完成收录行情信息任务。 - -![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/data_recoder/start.png) - -  - -下面介绍行情收录的具体原理:若无合约记录的历史,用户需要先添加行情记录任务,如连接CTP接口后记录rb1905.SHFE的tick数据,然后调用add_tick_recording()函数执行下面工作: -1) 先创建tick_recordings字典; -2) 调用接口的suscribe()函数订阅行情; -3 )保存该tick_recordings字典到json文件上; -4) 推送行情记录事件。 - -``` - def add_tick_recording(self, vt_symbol: str): - """""" - if vt_symbol in self.tick_recordings: - self.write_log(f"已在Tick记录列表中:{vt_symbol}") - return - - contract = self.main_engine.get_contract(vt_symbol) - if not contract: - self.write_log(f"找不到合约:{vt_symbol}") - return - - self.tick_recordings[vt_symbol] = {} - "symbol": contract.symbol, - "exchange": contract.exchange.value, - "gateway_name": contract.gateway_name - } - - self.subscribe(contract) - self.save_setting() - self.put_event() - - self.write_log(f"添加Tick记录成功:{vt_symbol}") -``` - -下面对add_tick_recording()函数里面调用的子函数进行扩展: - -### 订阅行情 - -调用main_engine的suscribe()函数来订阅行情,需要填入的信息为symbol、exchange、gateway_name -``` - def subscribe(self, contract: ContractData): - """""" - req = SubscribeRequest( - symbol=contract.symbol, - exchange=contract.exchange - ) - self.main_engine.subscribe(req, contract.gateway_name) -``` - -  - -### 将订阅信息保存到json文件 - -- 主要把tick_recordings或者bar_recordings通过save_json()函数保存到C:\Users\Administrator\\.vntrader文件夹内的data_recorder_setting.json上。 -- 该json文件用于存放行情记录的任务,当每次启动行情模块后,会调用load_setting()函数来得到tick_recordings和bar_recordings字典,进而开始记录的任务。 -``` -setting_filename = "data_recorder_setting.json" - def save_setting(self): - """""" - setting = { - "tick": self.tick_recordings, - "bar": self.bar_recordings - } - save_json(self.setting_filename, setting) - - def load_setting(self): - """""" - setting = load_json(self.setting_filename) - self.tick_recordings = setting.get("tick", {}) - self.bar_recordings = setting.get("bar", {}) -``` - -  - -### 推送行情记录事件 - -- 创建行情记录列表tick_symbols和bar_symbols,并且缓存在data字典里; -- 创建evnte对象,其类型是EVENT_RECORDER_UPDATE, 内容是data字典; -- 调用event_engine的put()函数推送event事件。 - -``` - def put_event(self): - """""" - tick_symbols = list(self.tick_recordings.keys()) - tick_symbols.sort() - - bar_symbols = list(self.bar_recordings.keys()) - bar_symbols.sort() - - data = { - "tick": tick_symbols, - "bar": bar_symbols - } - - event = Event( - EVENT_RECORDER_UPDATE, - data - ) - self.event_engine.put(event) -``` - -  - -### 注册行情记录事件 - -register_event()函数分别注册2种事件:EVENT_CONTRACT、EVENT_TICK -- EVENT_CONTRACT事件,调用的是process_contract_event()函数: 从tick_recordings和bar_recordings字典获取需要订阅的合约品种;然后使用subscribe()函数进行订阅行情。 -- EVENT_TICK事件,调用的是process_tick_event()函数:从tick_recordings和bar_recordings字典获取需要订阅的合约品种;然后使用record_tick()和record_bar()函数,把行情记录任务推送到queue队列中等待执行。 - -``` - def register_event(self): - """""" - self.event_engine.register(EVENT_TICK, self.process_tick_event) - self.event_engine.register(EVENT_CONTRACT, self.process_contract_event) - - def process_tick_event(self, event: Event): - """""" - tick = event.data - - if tick.vt_symbol in self.tick_recordings: - self.record_tick(tick) - - if tick.vt_symbol in self.bar_recordings: - bg = self.get_bar_generator(tick.vt_symbol) - bg.update_tick(tick) - - def process_contract_event(self, event: Event): - """""" - contract = event.data - vt_symbol = contract.vt_symbol - - if (vt_symbol in self.tick_recordings or vt_symbol in self.bar_recordings): - self.subscribe(contract) - - def record_tick(self, tick: TickData): - """""" - task = ("tick", copy(tick)) - self.queue.put(task) - - def record_bar(self, bar: BarData): - """""" - task = ("bar", copy(bar)) - self.queue.put(task) - - def get_bar_generator(self, vt_symbol: str): - """""" - bg = self.bar_generators.get(vt_symbol, None) - - if not bg: - bg = BarGenerator(self.record_bar) - self.bar_generators[vt_symbol] = bg - - return bg -``` - -  - -### 执行记录行情任务 - -在while循环中,从queue队列读取任务,调用save_tick_data()或者save_bar_data()函数来记录数据,并且载入到数据库中。 -``` - def run(self): - """""" - while self.active: - try: - task = self.queue.get(timeout=1) - task_type, data = task - - if task_type == "tick": - database_manager.save_tick_data([data]) - elif task_type == "bar": - database_manager.save_bar_data([data]) - - except Empty: - continue -``` - -  - - - - -## 移除记录 - -移除记录操作:输入需要移除合约品种的本地代码,如rb1905.SHFE。该本地代码必须在“Tick记录列表” 或者“K线记录列表”中。若要移除Tick记录,只需在”Tick记录“那一栏上点击”移除“按钮即可。 - -下面展示代码运作原理: - -- 从tick_recordings字典移除vt_symbol -- 调用save_setting()函数保存json配置文件 -- 推送最新的tick_recordings字典来继续记录行情,原来移除合约品种不再记录。 -``` - def remove_tick_recording(self, vt_symbol: str): - """""" - if vt_symbol not in self.tick_recordings: - self.write_log(f"不在Tick记录列表中:{vt_symbol}") - return - - self.tick_recordings.pop(vt_symbol) - self.save_setting() - self.put_event() - - self.write_log(f"移除Tick记录成功:{vt_symbol}") -``` - -  - -## 停止记录 - -停止记录操作:只需手动关闭行情记录模块窗口就停止记录行情。 - -- 记录行情状态改为False, 停止while循环; -- 调用join()函数关掉线程。 - -``` - def close(self): - """""" - self.active = False - - if self.thread.isAlive(): - self.thread.join() -``` \ No newline at end of file From 2c4d9d1cf6d907cdcc82d2da2547cfd112231eb8 Mon Sep 17 00:00:00 2001 From: 1122455801 Date: Fri, 17 May 2019 14:58:11 +0800 Subject: [PATCH 4/4] Update index.md --- docs/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/index.md b/docs/index.md index 86f7512f..1f78b1e9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -49,6 +49,10 @@ * [移除记录](datarecoder.md#移除记录) * [停止记录](datarecoder.md#停止记录) +* [算法交易](algo_trader.md) + * [模块构成](algo_trader#模块构成) + * [基本操作](algo_trader#基本操作) + * [算法示例](algo_trader#算法示例) * [交易接口](gateway.md) * [如何连接](gateway.md#如何连接)