使用嚮導介面 豐富細節的移倉助手
vntrader 自帶的移倉助手相當不錯,不過細節少了些。
我結合實際使用,使用嚮導介面,在豐富了一些細節,在原理程式碼上做了一個新版移倉助手。
第一頁介面
輸入移倉合約後,跳出需要移倉的策略。
這裡可以透過打勾選擇需要移倉的策略,如果策略不用移倉可以取消。這裡增加了一些錯誤判斷,比如目標合約不能是帶移倉合約。
第二頁介面
下一步後進入第二頁介面,上面是統計策略持倉和賬戶實際持倉;如果不一致,則會報錯;當然如果上一頁某些策略取消,則可能不一致,可以改成warning message。
另外這裡程式碼是按照淨倉模式來處理,如果是按照預設模式,需要改程式碼。
下半部頁面是移倉發單操作;因為有可能移倉手數太多,這個相當一個小型演算法交易,定義了每筆手數,如果是10,對於25就是拆分成三筆。
下面是超價,如果想使用市價單,把超價改為-1即可。
最後是每筆成交後,等待時間,如果3秒,則等上筆交易完成3秒後再發下一筆。
第三頁介面
上版部分是移倉指令的資訊彙總,中間是啟動移倉,下面是log報告
這裡面改動的地方是,新倉位的開倉價原來開倉價是加上新合約開倉價和舊合約平倉價的差值。比如舊合約開倉價格50,現在平倉價格70,新合約開倉價格80,那麼新合約的持倉價格是50+(80-70) = 60,包含了舊持倉20的盈利點位。
完成同時會在策略級別生成一個虛擬平倉單和虛擬開倉單,方便歷史統計計算。
程式碼如下,因為改動東西比較多,僅作參考。
from datetime import datetime from threading import Timer from time import sleep from typing import TYPE_CHECKING # from vnpy.trader.ui import QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import Qt from PyQt5.QtGui import QFont from PyQt5.QtWidgets import (QMessageBox, QFrame, QWizard, QWizardPage, QVBoxLayout, QGridLayout, QLabel) from vnpy.trader.constant import OrderType from vnpy.trader.converter import OffsetConverter, PositionHolding from vnpy.trader.database import database_manager from vnpy.trader.engine import MainEngine from vnpy.trader.event import ( EVENT_TRADE ) from vnpy.trader.object import ContractData, OrderRequest, SubscribeRequest, TickData from vnpy.trader.object import Direction, Offset from vnpy.trader.utility import round_to from ..base import StopOrder, StopOrderStatus from ..engine import CtaEngine, APP_NAME from ..template import CtaTemplate if TYPE_CHECKING: from .widget import CtaManager class WizardPage1(QWizardPage): def __init__(self, parent=None): super(WizardPage1, self).__init__(parent) self.parent = parent self.cta_manager: "CtaManager" = parent.cta_manager self.cta_engine: CtaEngine = parent.cta_manager.cta_engine self.main_engine: MainEngine = parent.cta_manager.main_engine self.init_ui() def init_ui(self): """""" self.setTitle("選擇移倉合約和策略") old_symbols = [] for vt_symbol, strategies in self.cta_engine.symbol_strategy_map.items(): if strategies: old_symbols.append(vt_symbol) self.old_symbol_combo = QtWidgets.QComboBox() self.old_symbol_combo.addItems(old_symbols) self.new_symbol_line = QtWidgets.QLineEdit() self.message_line = QtWidgets.QLabel() self.strategy_table = StrategyMonitor() self.strategy_table.setMinimumWidth(500) button = QtWidgets.QPushButton("待移倉策略") button.clicked.connect(self.display_traget_strategies) button.setFixedHeight(button.sizeHint().height() * 2) form = QtWidgets.QFormLayout() form.addRow("移倉合約", self.old_symbol_combo) form.addRow("目標合約", self.new_symbol_line) form.addRow(self.message_line) form.addRow(button) hbox = QtWidgets.QHBoxLayout() hbox.addLayout(form) hbox.addWidget(self.strategy_table) self.setLayout(hbox) def validatePage(self): self.strategy_table.actived_strategyies() if self.strategy_table.rollover_strategies_name: # (lambda x: x * x, [y for y in range(10)]) self.parent.rollover_strategies = [self.cta_engine.strategies[x] for x in self.strategy_table.rollover_strategies_name] self.parent.old_symbol = self.old_symbol_combo.currentText() if not self.new_symbol_line.text(): QMessageBox.warning(self, '資訊', '移倉目標合約為空') return False elif self.parent.old_symbol == self.new_symbol_line.text(): QMessageBox.warning(self, '資訊', '移倉目標重複') return False new_symbol = self.new_symbol_line.text() # 確認是否有這個合約 self.parent.subscribe(new_symbol) sleep(1) new_tick = self.main_engine.get_tick(new_symbol) if not new_tick: # self.setTitle(f"無法獲取目標合約{new_symbol}的盤口資料,請先訂閱行情") QMessageBox.warning(self, '資訊', f"無法獲取目標合約{new_symbol}的盤口資料,請先訂閱行情") return False contract = self.main_engine.get_contract(new_symbol) self.parent.priceTick = contract.pricetick self.parent.new_symbol = new_symbol return True else: # self.setTitle("沒有策略被選中") QMessageBox.warning(self, '資訊', f"沒有策略被選中") return False def display_traget_strategies(self): selected_vt_symbol = self.old_symbol_combo.currentText() strategies = self.cta_engine.symbol_strategy_map[selected_vt_symbol] self.strategy_table.setRowCount(0) self.strategy_table.update_data(strategies) class StrategyMonitor(QtWidgets.QTableWidget): """ Table monitor for parameters and variables. """ def __init__(self): """""" super(StrategyMonitor, self).__init__() self.rollover_strategies_name = [] self.init_ui() def init_ui(self): """""" labels = list(["選擇", "策略名稱", "持倉數"]) self.setColumnCount(len(labels)) self.setHorizontalHeaderLabels(labels) # self.setMaximumWidth(100) self.verticalHeader().setVisible(False) # self.verticalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) self.verticalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) self.horizontalHeader().setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch) def update_data(self, strategies): if strategies: for iterable, strategy in enumerate(strategies): self.insertRow(iterable) item_checked = QtWidgets.QTableWidgetItem() item_checked.setCheckState(Qt.Checked) item_checked.checkState() self.setItem(iterable, 0, item_checked) self.setItem(iterable, 1, QtWidgets.QTableWidgetItem(strategy.strategy_name)) self.setItem(iterable, 2, QtWidgets.QTableWidgetItem(str(strategy.pos))) def actived_strategyies(self): """""" rowCount = self.rowCount() if rowCount > 0: self.rollover_strategies_name = [] for rowId in range(rowCount): if self.item(rowId, 0).checkState(): # strategy = self.parent.cta_engine.strategies[self.item(rowId,1)] self.rollover_strategies_name.append(self.item(rowId, 1).text()) return self.rollover_strategies_name class WizardPage2(QWizardPage): def __init__(self, parent=None): super(WizardPage2, self).__init__(parent) self.parent = parent self.strategy_positive_pos = 0 self.strategy_negative_pos = 0 self.strategy_net_pos = 0 self.account_positive_pos = 0 self.account_negative_pos = 0 self.account_net_pos = 0 self._conclusion_list = { 0: "持倉待更新", 1: "策略淨持倉和賬戶合約淨持倉相等, 賬戶單向持倉,淨倉模式", 2: "策略淨持倉和賬戶合約淨持倉相等, 賬戶雙向持倉", 3: "策略淨持倉和賬戶合約淨持倉存在差異" } self.conclusion = 0 self.init_ui() def init_ui(self): """""" self.setTitle('移倉數量和賬戶持倉資料') AllvLayout = QVBoxLayout() # 中間視窗部分顯示的內容 vLayout = QGridLayout() self.strategy_info = QLabel() self.strategy_positive_info = QLabel() self.strategy_negative_info = QLabel() self.strategy_net_info = QLabel() vLayout.addWidget(self.strategy_info, 0, 0) vLayout.addWidget(self.strategy_positive_info, 1, 0) vLayout.addWidget(self.strategy_negative_info, 2, 0) vLayout.addWidget(self.strategy_net_info, 3, 0) frame = QFrame() # frame.setFrameStyle(QFrame.Box) self.accnout_info = QLabel() self.accnout_positive_info = QLabel() self.accnout_negative_info = QLabel() self.accnout_net_info = QLabel() vLayout.addWidget(self.accnout_info, 0, 1) vLayout.addWidget(self.accnout_positive_info, 1, 1) vLayout.addWidget(self.accnout_negative_info, 2, 1) vLayout.addWidget(self.accnout_net_info, 3, 1) frame.setLayout(vLayout) self.conclusion_info = QLabel() self.conclusion_info.setFont(QFont(self.conclusion_info.font().family(), 14)) self.conclusion_info.setAlignment(Qt.AlignCenter) frame2 = QFrame() form = QtWidgets.QFormLayout() self.max_order_count_spin = QtWidgets.QSpinBox() self.max_order_count_spin.setRange(1,5000) self.max_order_count_spin.setValue(100) self.wait_time_spin = QtWidgets.QSpinBox() self.wait_time_spin.setRange(0, 10000) self.payup_spin = QtWidgets.QSpinBox() self.payup_spin.setRange(-1,50000) self.payup_spin.setValue(2) self.wait_time_spin.setValue(3) form.addRow("交易單筆限額 ", self.max_order_count_spin) form.addRow("移倉發單超價", self.payup_spin) form.addRow(QLabel("超價設為 -1 時,按市價單發單")) form.addRow("單筆成交後等待(秒)", self.wait_time_spin) frame2.setLayout(form) AllvLayout.addWidget(frame) AllvLayout.addWidget(self.conclusion_info) AllvLayout.addWidget(frame2) self.setLayout(AllvLayout) self.setButtonText(QWizard.NextButton, '確定移倉') def initializePage(self): self.strategy_positive_pos = 0 self.strategy_negative_pos = 0 for strategy in self.parent.rollover_strategies: if strategy.pos > 0: self.strategy_positive_pos += strategy.pos elif strategy.pos < 0: self.strategy_negative_pos += strategy.pos self.strategy_net_pos = self.strategy_positive_pos + self.strategy_negative_pos self.strategy_info.setText(f"選取 {self.parent.old_symbol} 策略共: {len(self.parent.rollover_strategies)} 個") self.strategy_positive_info.setText(f"策略多倉共: {self.strategy_positive_pos}") self.strategy_negative_info.setText(f"策略空倉共: {abs(self.strategy_negative_pos)}") self.strategy_net_info.setText(f"策略淨持倉共: {self.strategy_net_pos}") current_holding = self.parent.current_position() self.account_positive_pos = current_holding.long_pos self.account_negative_pos = -current_holding.short_pos self.account_net_pos = self.account_positive_pos + self.account_negative_pos self.accnout_info.setText(f"賬戶當前合約: {self.parent.old_symbol}") self.accnout_positive_info.setText(f"賬戶多倉共: {self.account_positive_pos}") self.accnout_negative_info.setText(f"賬戶空倉共: {abs(self.account_negative_pos)}") self.accnout_net_info.setText(f"賬戶淨持倉共: {self.account_net_pos}") if self.account_net_pos == self.strategy_net_pos and ( self.account_negative_pos == 0 or self.account_positive_pos == 0): self.conclusion = 1 self.parent.move_position = self.strategy_net_pos elif self.account_net_pos == self.strategy_net_pos and self.account_negative_pos != 0 and self.account_positive_pos != 0: self.conclusion = 2 elif self.account_net_pos != self.strategy_net_pos: self.conclusion = 3 self.conclusion_info.setText(self._conclusion_list[self.conclusion]) def validatePage(self): if self.conclusion == 1: self.parent.ROLL_OVER_MAX = self.max_order_count_spin.value() self.parent.trade_wait_time = self.wait_time_spin.value() self.parent.payup = self.payup_spin.value() return True else: QMessageBox.warning(self, '資訊', self._conclusion_list[self.conclusion]) return False class WizardPage3(QWizardPage): def __init__(self, parent=None): super(WizardPage3, self).__init__(parent) self.parent = parent self.init_ui() def init_ui(self): self.setTitle("移倉交易") self.setMinimumHeight(600) vboxLayout = QtWidgets.QVBoxLayout() self.old_symbol_info = QLabel() self.new_symbol_info = QLabel() self.move_pistion = QLabel() self.move_strategy = QLabel() self.roll_over_info = QLabel() form = QtWidgets.QFormLayout() form.addRow("移倉合約 ", self.old_symbol_info) form.addRow("目標合約 ", self.new_symbol_info) form.addRow("委託移倉數量 ", self.move_pistion) form.addRow("更新策略 ", self.move_strategy) form.addRow("交易說明 ", self.roll_over_info) button = QtWidgets.QPushButton("移倉啟動") button.clicked.connect(self.parent.roll_all) button.setFixedHeight(button.sizeHint().height() * 2) self.log_edit = QtWidgets.QTextEdit() self.log_edit.setReadOnly(True) self.log_edit.setMinimumWidth(500) self.log_edit.setMinimumHeight(200) vboxLayout.addLayout(form) vboxLayout.addWidget(button) vboxLayout.addWidget(self.log_edit) self.setLayout(vboxLayout) def initializePage(self): self.old_symbol_info.setText(self.parent.old_symbol) self.new_symbol_info.setText(self.parent.new_symbol) self.move_pistion.setText(str(self.parent.move_position)) textline = "" for strategy in self.parent.rollover_strategies: textline += f"策略: {strategy.strategy_name} 倉位: {strategy.pos}" + "\n" self.move_strategy.setText(textline) roundCount = abs(self.parent.move_position) // self.parent.ROLL_OVER_MAX self.parent.request_split_list = [self.parent.ROLL_OVER_MAX for x in range(roundCount)] lastAmount = abs(self.parent.move_position) - self.parent.ROLL_OVER_MAX * roundCount if lastAmount != 0: self.parent.request_split_list.append(abs(self.parent.move_position) - self.parent.ROLL_OVER_MAX * roundCount) self.parent.send_count = len(self.parent.request_split_list) sendMessage = "按照市價" if self.parent.payup < 0 else "市場價格加超價" + str(self.parent.payup) if self.parent.send_count > 0: self.roll_over_info.setText(f"移倉手數: {self.parent.move_position}; 發單限額: {self.parent.ROLL_OVER_MAX} \n" + f"交易將會分: {self.parent.send_count} 次發出; 每次筆數為 {self.parent.request_split_list} \n"+ sendMessage + f"發單, 每個交易完成後等待{self.parent.trade_wait_time}秒\n") elif self.parent.move_position !=0: self.roll_over_info.setText(f"交易將會單次發出; 按當前" + sendMessage + f"發單") elif self.parent.move_position ==0: self.roll_over_info.setText(f"無需交易,僅作策略合約切換") class RolloverTool(QWizard): """""" log_signal: QtCore.pyqtSignal = QtCore.pyqtSignal(str) # trade_signal: QtCore.pyqtSignal = QtCore.pyqtSignal(Event) def __init__(self, cta_manager: "CtaManager") -> None: """""" super().__init__() self.cta_manager: "CtaManager" = cta_manager self.event_engine = cta_manager.event_engine self.cta_engine: CtaEngine = cta_manager.cta_engine self.main_engine: MainEngine = cta_manager.main_engine self.rollover_strategies = [] self.new_strategies = [] self.old_symbol = "" self.new_symbol = "" self.move_position = 0 self.ROLL_OVER_MAX = 100 self.send_count = 0 self.request_split_list = [] self.request_count = 0 self.payup = 0 self.trade_wait_time = 3 self.deal_volume = 0 self.priceTick = 0 self.old_completed_traders = 0 self.new_completed_traders = 0 self.new_vt_orderids = [] self.old_vt_orderids = [] self.new_vt_traders = [] self.old_vt_traders = [] self.total_new_vt_traders = [] self.total_old_vt_traders = [] self.page1 = WizardPage1(self) self.page2 = WizardPage2(self) self.page3 = WizardPage3(self) self.register_event() self.log_signal.connect(self.log_txt_append) self.init_ui() def register_event(self): """""" # self.trade_signal.connect(self.process_trade_event) self.event_engine.register(EVENT_TRADE, self.process_trade_event) def process_trade_event(self, event): trade = event.data if trade.vt_orderid in self.old_vt_orderids: self.old_vt_traders.append((trade.volume,trade.price)) self.old_completed_traders +=trade.volume elif trade.vt_orderid in self.new_vt_orderids: self.new_vt_traders.append((trade.volume,trade.price)) self.new_completed_traders +=trade.volume else: return if self.new_completed_traders == 0 or self.old_completed_traders == 0: return if self.send_count == 0 and self.old_completed_traders == self.deal_volume and self.new_completed_traders == self.deal_volume: self.update_strategies(self.old_vt_traders,self.new_vt_traders) elif self.send_count != 0 and self.old_completed_traders == self.deal_volume and self.new_completed_traders == self.deal_volume: self.total_old_vt_traders.extend(self.old_vt_traders) self.total_new_vt_traders.extend(self.new_vt_traders) self.write_log(f"第({self.request_count+1})筆移倉交易完成,移倉數量:{self.deal_volume}") if self.request_count == self.send_count: self.update_strategies(self.total_old_vt_traders,self.total_new_vt_traders) return # sleep(self.trade_wait_time) wait_Timer = Timer(self.trade_wait_time,self.next_trade_request) self.write_log(f"等待{self.trade_wait_time}秒後啟動下一個筆交易") wait_Timer.start() def next_trade_request(self): self.old_vt_traders = [] self.new_vt_traders = [] self.old_completed_traders = 0 self.new_completed_traders = 0 self.deal_volume = self.request_split_list[self.request_count] self.roll_position(self.old_symbol, self.new_symbol, self.payup) self.request_count += 1 def init_ui(self): self.setPage(0, self.page1) self.setPage(1, self.page2) self.setPage(2, self.page3) # 去掉幫助按鈕 self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) # 視窗最小化 self.setWindowFlags(Qt.WindowMinimizeButtonHint|Qt.WindowCloseButtonHint) # 設定導航樣式 self.setWizardStyle(QWizard.ModernStyle) # 設定導航視窗標題 self.setWindowTitle("移倉助手") # 去掉頁面的一些按鈕 self.setOption(QWizard.NoBackButtonOnStartPage) # 首頁沒有回退按鈕 # self.setOption(QWizard.NoBackButtonOnLastPage) # 最後一頁沒有回退按鈕 self.setOption(QWizard.NoCancelButton) # 沒有取消按鈕 # 設定按鈕的顯示名稱 self.setButtonText(QWizard.NextButton, '下一步') self.setButtonText(QWizard.BackButton, '上一步') self.setButtonText(QWizard.FinishButton, '完成') def write_log(self, text: str) -> None: """""" now = datetime.now() text = now.strftime("%H:%M:%S\t") + text self.log_signal.emit(text) self.main_engine.write_log(text) def log_txt_append(self,text): self.page3.log_edit.append(text) self.page3.log_edit.moveCursor(QtGui.QTextCursor.End) def subscribe(self, vt_symbol: str) -> None: """""" contract = self.main_engine.get_contract(vt_symbol) if not contract: return req = SubscribeRequest(contract.symbol, contract.exchange) self.main_engine.subscribe(req, contract.gateway_name) def roll_all(self) -> None: """""" # Check all strategies inited (pos data loaded from disk json file) for strategy in self.rollover_strategies: if not strategy.inited: self.write_log(f"策略{strategy.strategy_name}尚未初始化,無法執行移倉") return if strategy.trading: self.write_log(f"策略{strategy.strategy_name}是交易狀態,將停止交易") self.cta_engine.stop_strategy(strategy.strategy_name) self.write_log(f"策略{strategy.strategy_name}已經停止交易") # self.setOption(QWizard.NoBackButtonOnLastPage) # self.setEnabled(False) # Roll position first if self.send_count == 0: self.deal_volume = abs(self.move_position) self.roll_position(self.old_symbol, self.new_symbol, self.payup) else: self.deal_volume = self.request_split_list[self.request_count] self.roll_position(self.old_symbol, self.new_symbol, self.payup) self.request_count +=1 # Disable self def rollover_price_diff(self,old_tuplelist, new_tuplelist): old_average_price = self.calculte_average(old_tuplelist) self.write_log(f"舊合約平倉均價:{round_to(old_average_price,self.priceTick)}") new_average_price = self.calculte_average(new_tuplelist) self.write_log(f"目標合約開倉均價:{round_to(new_average_price,self.priceTick)}") price_diff = new_average_price - old_average_price self.write_log(f"新舊移倉差價:{price_diff}") return price_diff def calculte_average(self, tuplelist): total_volume= 0 total_price = 0 for tupleOne in tuplelist: total_volume += tupleOne[0] total_price += tupleOne[0]*tupleOne[1] return total_price/total_volume def current_position(self) -> PositionHolding: """""" converter = self.cta_engine.offset_converter holding: PositionHolding = converter.get_position_holding(self.old_symbol) return holding def roll_position(self, old_symbol: str, new_symbol: str, payup: int) -> None: """""" converter = self.cta_engine.offset_converter holding: PositionHolding = converter.get_position_holding(old_symbol) if self.deal_volume == 0: self.write_log(f"無需交易,移倉數量:{self.deal_volume}") self.update_strategies(self.old_vt_traders,self.new_vt_traders) return if holding.long_pos: # if holding.long_pos != self.move_position: # QMessageBox.warning(self, '資訊', f"賬戶持倉數量改變,請退回") # return self.old_vt_orderids = self.send_order( old_symbol, Direction.SHORT, Offset.CLOSE, payup, self.deal_volume ) self.new_vt_orderids = self.send_order( new_symbol, Direction.LONG, Offset.OPEN, payup, self.deal_volume ) # Roll short postiion if holding.short_pos: # if holding.short_pos != self.move_position: # QMessageBox.warning(self, '資訊', f"賬戶持倉數量改變,請退回") # return self.old_vt_orderids = self.send_order( old_symbol, Direction.LONG, Offset.CLOSE, payup, self.deal_volume ) self.new_vt_orderids = self.send_order( new_symbol, Direction.SHORT, Offset.OPEN, payup, self.deal_volume ) self.write_log(f"第({self.request_count+1})筆移倉交易請求發出,移倉數量:{self.deal_volume}") def update_strategies(self,old_vt_traders,new_vt_traders): """when deal complete, update_strategies""" self.write_log(f"===========持倉更新完成,開始更新策略, 請完成後再關閉視窗============") if old_vt_traders and new_vt_traders: price_diff = self.rollover_price_diff(old_vt_traders,new_vt_traders) else: old_tick: TickData = self.main_engine.get_tick(self.old_symbol) new_tick: TickData = self.main_engine.get_tick(self.new_symbol) price_diff = new_tick.last_price - old_tick.last_price # Then roll strategy for strategy in self.rollover_strategies: self.roll_strategy(strategy, self.new_symbol, price_diff) check_Timer = Timer(5, self.check_update_strategies) check_Timer.start() def check_update_strategies(self): if self.new_strategies: for new_strategy in self.new_strategies: if new_strategy.inited: self.cta_engine.start_strategy(new_strategy.strategy_name) self.write_log(f"更新策略 [{new_strategy.strategy_name}] 初始化完成,啟動完成") self.new_strategies.remove(new_strategy) check_Timer = Timer(5,self.check_update_strategies) check_Timer.start() else: self.write_log(f"==========={self.old_symbol} -> {self.new_symbol} 移倉完成 請關閉視窗 ============") self.setEnabled(True) def roll_strategy(self, strategy: CtaTemplate, vt_symbol: str, price_diff) -> None: """""" if not strategy.inited: self.cta_engine._init_strategy(strategy.strategy_name) # Save data of old strategy pos = strategy.pos name = strategy.strategy_name vt_local = strategy.vt_local parameters = strategy.get_parameters() if pos !=0: new_price = round_to(strategy.PosPrice + price_diff, self.priceTick) else: new_price = 0 # Remove old strategy result = self.cta_engine.remove_strategy(name) if result: self.cta_manager.remove_strategy(name) self.write_log(f"移除老策略 [{name}] [{strategy.vt_symbol}],倉位:{strategy.pos}, 原價格:{strategy.PosPrice}") # Add new strategy if ("init_pos" in parameters) and ("init_entry_price" in parameters): parameters["init_entry_price"] = new_price # Add new strategy self.cta_engine.add_strategy( strategy.__class__.__name__, name, vt_symbol, vt_local, parameters ) # Init new strategy self.cta_engine.init_strategy(name) # Update pos to new strategy new_strategy: CtaTemplate = self.cta_engine.strategies[name] new_strategy.pos = pos new_strategy.PosPrice = new_price self.cta_engine.sync_strategy_data(new_strategy) self.cta_engine.put_strategy_event(new_strategy) self.new_strategies.append(new_strategy) self.write_log(f"更新策略 [{name}] [{vt_symbol}]完成,倉位:{new_strategy.pos}, 價格:{new_price}") # Save close and open dummy deal to database if strategy.pos == 0: return elif strategy.pos > 0: close_old_direction = Direction.SHORT open_new_direction = Direction.LONG elif strategy.pos < 0: close_old_direction = Direction.LONG open_new_direction = Direction.SHORT dummy_close_old_strategy_order = StopOrder( vt_symbol= strategy.vt_symbol, direction = close_old_direction, offset = Offset.CLOSE, price = strategy.PosPrice, volume = pos, stop_orderid = f"{name}_{strategy.vt_symbol}_{vt_symbol}_Rollover", strategy_name = name, datetime = datetime.now(), lock = False, net = False, vt_orderids = [], status = StopOrderStatus.TRIGGERED ) dummy_close_old_strategy_order.completed_volume = pos dummy_close_old_strategy_order.average_price = strategy.PosPrice dummy_close_old_strategy_order.first_price = strategy.PosPrice dummy_close_old_strategy_order.triggered_price = strategy.PosPrice database_manager.save_triggered_stop_order_data(dummy_close_old_strategy_order) dummy_open_new_strategy_order = StopOrder( vt_symbol= vt_symbol, direction = open_new_direction, offset = Offset.OPEN, price = new_price, volume = pos, stop_orderid = f"{name}_{strategy.vt_symbol}_{vt_symbol}_Rollover", strategy_name = name, datetime = datetime.now(), lock = False, net = False, vt_orderids = [], status = StopOrderStatus.TRIGGERED ) dummy_open_new_strategy_order.completed_volume = pos dummy_open_new_strategy_order.average_price = new_price dummy_open_new_strategy_order.first_price = new_price dummy_open_new_strategy_order.triggered_price = new_price database_manager.save_triggered_stop_order_data(dummy_open_new_strategy_order) self.write_log(f"虛擬平倉單已經錄入資料庫") def send_order( self, vt_symbol: str, direction: Direction, offset: Offset, payup: int, volume: float, ): """ Send a new order to server. """ contract: ContractData = self.main_engine.get_contract(vt_symbol) tick: TickData = self.main_engine.get_tick(vt_symbol) offset_converter: OffsetConverter = self.cta_engine.offset_converter if self.payup >= 0: if direction == Direction.LONG: price = tick.ask_price_1 + contract.pricetick * payup else: price = tick.bid_price_1 - contract.pricetick * payup else: if direction == Direction.LONG: if tick.limit_up: price = tick.limit_up else: price = tick.ask_price_5 else: if tick.limit_down: price = tick.limit_down else: price = tick.bid_price_5 original_req: OrderRequest = OrderRequest( symbol=contract.symbol, exchange=contract.exchange, direction=direction, offset=offset, type=OrderType.LIMIT, price=price, volume=volume, reference=f"{APP_NAME}_Rollover" ) req_list = offset_converter.convert_order_request(original_req, False, False) vt_orderids = [] for req in req_list: vt_orderid = self.main_engine.send_order(req, contract.gateway_name) if not vt_orderid: continue vt_orderids.append(vt_orderid) offset_converter.update_order_request(req, vt_orderid) msg = f"發出委託{vt_symbol},{direction.value} {offset.value},{volume}@{price}" self.write_log(msg) return vt_orderids
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22259926/viewspace-2919374/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Spring IoC註解式開發無敵詳細(細節豐富)Spring
- 使用 Linux cowsay 製作豐富多彩的節日問候Linux
- 如何用UE高效生成細節豐富的《重生邊緣》野外場景(上)
- 如何用UE高效生成細節豐富的《重生邊緣》野外場景(下)
- RK3588開發板豐富的功能介面
- 使用JSPWiki豐富Unity-UPM包的使用JSUnity
- 豐富 pytest 的 assert
- 使用 LogProperties source generator 豐富日誌
- Vivado使用技巧(30):使用時序約束嚮導
- 基於Bootstrap的jQuery使用者嚮導外掛bootjQuery
- .Net Core 使用 TagProvider 與 Enricher 豐富日誌IDE
- 在細節豐富的歐洲城市裡尋找寶藏,《迷宮大偵探》開發團隊專訪
- win10系統使用“焦點嚮導”的方法【圖文】Win10
- MongoDB學習之豐富的索引MongoDB索引
- 豐富多彩的會員活動。
- OpenFeign 使用細節
- 用可組合的構建塊豐富使用者介面?谷歌提出「可解釋性」的最新詮釋谷歌
- OAuth2.0最簡嚮導OAuth
- [JAVA] Java switch的使用細節Java
- 豐富的包(packages)生態系統Package
- 【cypress】4. 豐富的除錯工具除錯
- 使用 yo 命令列嚮導建立 SAP UI5 應用命令列UI
- 容易忽視的細節:Log4j 配置導致的零點介面嚴重超時
- mini-GPT4o來了? 能看、能聽、會說,還情感豐富的多模態全能助手EMOVAGPT
- Dynamics 365 配置IFD的嚮導介面下一步按鈕禁用的解決辦法
- AR人臉道具SDK,打造豐富使用者體驗
- Docker 19.03.13的四個使用細節Docker
- vue元件使用的細節 is 屬性Vue元件
- Termux使用的一些細節UX
- win10中windows元件嚮導在哪 win10系統怎樣啟動Windows元件嚮導Win10Windows元件
- Spring(4)-AOP使用細節Spring
- GO 變數使用細節Go變數
- MusicLibrary-一個豐富的音訊播放SDK。音訊
- 乾貨 | APP介面設計的色彩注意細節,有哪些?APP
- 使用Covermap實現地形細節
- 移動App網路優化細節探討APP優化
- Learn Forge tutorial - 嚮導式Forge進階教程
- Tun/Tap介面使用指導