代码测试与整理

This commit is contained in:
2025-11-14 11:45:42 +08:00
parent f5d37eaa7e
commit a18c7be7eb
5 changed files with 108 additions and 153 deletions
+2
View File
@@ -5,6 +5,8 @@ ActionEnableMarketData = "enable_market_data"
ActionDisableMarketData = "disable_market_data" ActionDisableMarketData = "disable_market_data"
MarketDataEnabled = "market_data_enabled" MarketDataEnabled = "market_data_enabled"
MarketDataDisabled = "market_data_disabled" MarketDataDisabled = "market_data_disabled"
MarketOrderCreated = "market_order_created"
MarketOrderTraded = "market_order_traded"
# Pring Log # Pring Log
EventPrintLog = "print_log" EventPrintLog = "print_log"
+3 -3
View File
@@ -165,7 +165,7 @@ class QmtV(XtQuantTraderCallback):
:param order: XtOrder对象 :param order: XtOrder对象
:return: :return:
""" """
pass print(f"委托回调 on_stock_order 投资备注 {order.strategy_name} {order.order_remark}")
# print(f'orderd {order.strategy_name}-{order.stock_code} {order.order_id} {order.order_volume}-{order.order_status}') # print(f'orderd {order.strategy_name}-{order.stock_code} {order.order_id} {order.order_volume}-{order.order_status}')
# stockCode = order.stock_code # stockCode = order.stock_code
# ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode] # ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode]
@@ -183,7 +183,7 @@ class QmtV(XtQuantTraderCallback):
:param trade: XtTrade对象 :param trade: XtTrade对象
:return: :return:
""" """
print(f"委托回调 投资备注 {trade.stock_code}-{trade.instrument_name} {trade.strategy_name} 不匹配 {trade.order_remark}") eBus.event_bus.publish(eBus.MarketOrderTraded, trade)
# stockCode = trade.stock_code # stockCode = trade.stock_code
# ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode] # ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode]
# # 如果存在对应的StockTradeController,则调用其onDataUpdate方法 # # 如果存在对应的StockTradeController,则调用其onDataUpdate方法
@@ -193,7 +193,7 @@ class QmtV(XtQuantTraderCallback):
# print(f"委托回调 投资备注 {trade.strategy_name} 不匹配 {ctrl.getName()}") # print(f"委托回调 投资备注 {trade.strategy_name} 不匹配 {ctrl.getName()}")
def on_order_stock_async_response(self, response:XtOrderResponse): def on_order_stock_async_response(self, response:XtOrderResponse):
print(f"委托回调 投资备注 {response.error_msg}{response.strategy_name} {response.order_remark}") print(f"委托回调 on_order_stock_async_response 投资备注 {response.error_msg}{response.strategy_name} {response.order_remark}")
# stockCode = response.order_remark # stockCode = response.order_remark
# ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode] # ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode]
+80 -70
View File
@@ -1,15 +1,16 @@
from core.logger import LogLevel, PrintLog
from core.qmt import qmtv from core.qmt import qmtv
from core.sfgrid.bus_events import EventTradeTargetUpdate from core.sfgrid.bus_events import EventTradeTargetUpdate
import core.sfgrid.model as model import core.sfgrid.model as model
from core import constants from core import constants
from core.eventbus import event_bus from core.eventbus import event_bus
from core.constants import OrderTypeBuy, OrderTypeInit, OrderTypeSell from core.constants import OrderTypeBuy, OrderTypeInit, OrderTypeSell
from core.util import queryPendingOrder, is_trading_time from core.util import is_trading_time
from xtquant import xtconstant from xtquant import xtconstant
from xtquant.xttype import XtOrder, XtTrade from xtquant.xttype import XtOrder, XtOrderResponse, XtTrade
import config
import threading import threading
import core.eventbus as eBus
class SFGridStrategy: class SFGridStrategy:
@@ -17,18 +18,21 @@ class SFGridStrategy:
def __init__(self, tradeTarget: model.SFGridTradeTarget): def __init__(self, tradeTarget: model.SFGridTradeTarget):
self.tradeTarget:model.SFGridTradeTarget = tradeTarget self.tradeTarget:model.SFGridTradeTarget = tradeTarget
self.enabledTrading(tradeTarget.enabled) # type: ignore self.enabledTrading(tradeTarget.enabled) # type: ignore
event_bus.subscribe(eBus.MarketOrderTraded, self.onOrderTrade)
self.refreshPlanPrice()
self.dataUpdateLock = threading.Lock() self.dataUpdateLock = threading.Lock()
def updateTradeTarget(self, inTradeTarget:model.SFGridTradeTarget): def updateTradeTarget(self, inTradeTarget:model.SFGridTradeTarget):
print(f'|- 标的{self.tradeTarget.targetName()}信息更新: START') PrintLog(LogLevel.INFO, f'|- 标的{self.tradeTarget.targetName()}信息更新: START')
self.dataUpdateLock.acquire() self.dataUpdateLock.acquire()
print(f'|- 标的{self.tradeTarget.targetName()}信息更新: LOCKED') PrintLog(LogLevel.INFO ,f'|- 标的{self.tradeTarget.targetName()}信息更新: LOCKED')
try: try:
self.tradeTarget = inTradeTarget self.tradeTarget = inTradeTarget
finally: finally:
print(f'|- 标的{self.tradeTarget.targetName()}信息更新: UNLOCKED') PrintLog(LogLevel.INFO ,f'|- 标的{self.tradeTarget.targetName()}信息更新: UNLOCKED')
self.dataUpdateLock.release() self.dataUpdateLock.release()
print(f'|- 标的{self.tradeTarget.targetName()}信息更新: END') self.refreshPlanPrice()
PrintLog(LogLevel.INFO ,f'|- 标的{self.tradeTarget.targetName()}信息更新: END')
def enabledTrading(self, enabled: bool) -> model.SFGridTradeTarget: def enabledTrading(self, enabled: bool) -> model.SFGridTradeTarget:
self.tradeTarget.enabled = enabled # type: ignore self.tradeTarget.enabled = enabled # type: ignore
@@ -49,6 +53,10 @@ class SFGridStrategy:
print(f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}, 交易启动失败') print(f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}, 交易启动失败')
self.tradeTarget.enabled = False # type: ignore self.tradeTarget.enabled = False # type: ignore
else: else:
orders = qmtv.queryPendingOrder(self.tradeTarget.stock_code, self.getName()) # type: ignore
for order in orders:
qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id)
print(f' |- 取消未成交订单 {len(orders)}')
print(f" |- 标的{self.tradeTarget.targetName()}交易监控暂停") print(f" |- 标的{self.tradeTarget.targetName()}交易监控暂停")
self.saveProxy() self.saveProxy()
@@ -63,12 +71,12 @@ class SFGridStrategy:
if not is_trading_time(): if not is_trading_time():
return return
if not self.tradeTarget.enabled: # 未建仓,自动交易暂停 if not self.tradeTarget.enabled: # 策略中止,自动交易暂停
return return
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - START') PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - START')
self.dataUpdateLock.acquire() self.dataUpdateLock.acquire()
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - LOCKED') PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - LOCKED')
try: try:
lastPrice = inTradeTarget.market_price lastPrice = inTradeTarget.market_price
@@ -77,27 +85,29 @@ class SFGridStrategy:
index: int = self.tradeTarget.grid_index # pyright: ignore[reportAssignmentType] index: int = self.tradeTarget.grid_index # pyright: ignore[reportAssignmentType]
orderRemark= "" orderRemark= ""
gridBasePrice = -1 if index>=len(inTradeTarget.getPriceGrid()) or index < 0 else inTradeTarget.getPriceGrid()[int(index)] # pyright: ignore[reportArgumentType] PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 策略运行状态{self.tradeTarget.enabled}, 初始化状态{self.tradeTarget.status}')
PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 当前价{lastPrice}')
if self.tradeTarget.enabled and self.tradeTarget.status == 0 and lastPrice <= inTradeTarget.getPriceGrid()[1]: # 已启用,未建仓,建仓 PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 网格索引{index}, 网格价格{self.tradeTarget.getPriceGrid()[index]}')
PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 计划买入价{self.tradeTarget.plan_buy_price}, 计划卖出价{self.tradeTarget.plan_sell_price}')
if self.tradeTarget.enabled and self.tradeTarget.status == 0 and lastPrice <= inTradeTarget.getPriceGrid()[1]: # 已启用,未建仓,准备建仓单信息
PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 准备建仓单信息')
orderPrice = inTradeTarget.getPriceGrid()[index] orderPrice = inTradeTarget.getPriceGrid()[index]
orderType = xtconstant.STOCK_BUY orderType = xtconstant.STOCK_BUY
orderRemark = OrderTypeInit orderRemark = OrderTypeInit
elif self.tradeTarget.enabled and self.tradeTarget.status == 1 and self.tradeTarget.plan_buy_price > 0 and lastPrice <= self.tradeTarget.plan_buy_price:
if self.tradeTarget.enabled and self.tradeTarget.status == 1: # 已启用,已建仓,网格单 # 已启用,已建仓,准备网格多单信息
lowPrice = -1 if index+1>=len(inTradeTarget.getPriceGrid()) else inTradeTarget.getPriceGrid()[int(index) + 1] # pyright: ignore[reportArgumentType] PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 准备网格多单信息')
highPrice = inTradeTarget.getPriceGrid()[index - 1] orderPrice = self.tradeTarget.plan_buy_price # type: ignore
orderType = xtconstant.STOCK_BUY
orderRemark = OrderTypeBuy
elif self.tradeTarget.enabled and self.tradeTarget.status == 1 and self.tradeTarget.plan_buy_price > 0 and lastPrice >= self.tradeTarget.plan_sell_price:
# 已启用,已建仓,准备网格空单信息
PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 准备网格空单信息')
orderPrice = self.tradeTarget.plan_sell_price # type: ignore
orderType = xtconstant.STOCK_SELL
orderRemark = OrderTypeSell
if lastPrice <= lowPrice: # 下下方多单 PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 下单信息: {orderType}, {orderPrice}, {orderRemark}')
orderPrice = lowPrice
orderType = xtconstant.STOCK_BUY
orderRemark = OrderTypeBuy
elif lastPrice >= highPrice: # 下上方空单
orderPrice = highPrice
orderType = xtconstant.STOCK_SELL
orderRemark = OrderTypeSell
if orderType != -1: if orderType != -1:
orders = qmtv.queryPendingOrder(str(self.tradeTarget.stock_code), self.getName()) orders = qmtv.queryPendingOrder(str(self.tradeTarget.stock_code), self.getName())
if len([order for order in orders if order.order_type == orderType and order.price == orderPrice]) > 0: if len([order for order in orders if order.order_type == orderType and order.price == orderPrice]) > 0:
@@ -121,94 +131,94 @@ class SFGridStrategy:
orderTypeName = "空单" orderTypeName = "空单"
elif orderRemark == OrderTypeInit: elif orderRemark == OrderTypeInit:
orderTypeName = "建仓单" orderTypeName = "建仓单"
print(f' |- {orderTypeName}委托, 单号 {self.tradeTarget.current_order_no}, 网格基准价 {gridBasePrice}, 下单价 {orderPrice}, 下单量 {self.tradeTarget.grid_volume}') gridBasePrice = -1 if index>=len(inTradeTarget.getPriceGrid()) or index < 0 else inTradeTarget.getPriceGrid()[int(index)] # pyright: ignore[reportArgumentType]
PrintLog(LogLevel.INFO, f' |- {orderTypeName}委托, 单号 {self.tradeTarget.current_order_no}, 网格基准价 {gridBasePrice}, 下单价 {orderPrice}, 下单量 {self.tradeTarget.grid_volume}')
finally: finally:
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - release lock') print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - release lock')
self.saveProxy() self.saveProxy()
self.dataUpdateLock.release() self.dataUpdateLock.release()
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - END') print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - END')
def onOrderCreate(self, order:XtOrder):
if order.strategy_name == self.getName():
print(f"委托创建通知 onOrderCreate[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]: {order.order_id}")
self.tradeTarget.current_order_no = order.order_id
self.saveProxy()
# def onAsyncOrderResponse(self, order:XtOrder): def onOrderCreateAsync(self, response:XtOrderResponse):
# print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:START') if response.strategy_name == self.getName():
# self.dataUpdateLock.acquire() print(f"委托创建通知 onOrderCreateAsync[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]: {response.order_id}")
# print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:LOCKED') self.tradeTarget.current_order_no = response.order_id
# try: self.saveProxy()
# if order.strategy_name == self.getName():
# self.tradeTarget.current_order_no = order.order_id
# self.tradeTarget.current_order_type = order.order_remark
# self.saveProxy()
# else:
# print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]: 不在策略监控范围内{order.strategy_name}')
# finally:
# print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:release lock')
# self.dataUpdateLock.release()
# print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:END')
def onOrderTrade(self, trade:XtTrade): def onOrderTrade(self, trade:XtTrade):
if trade.strategy_name != self.getName():
print(f"委托回调 投资备注 {trade.stock_code}-{trade.instrument_name} {trade.strategy_name} 不匹配 {trade.order_remark}")
return
print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:START, {trade.order_id}') print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:START, {trade.order_id}')
self.dataUpdateLock.acquire() self.dataUpdateLock.acquire()
print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:LOCKED') print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:LOCKED')
try: try:
if not trade.strategy_name == self.getName(): type:str = ""
print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]: 不在策略监控范围内{trade.strategy_name}')
return
if self.tradeTarget.status == 0 and trade.order_id == self.tradeTarget.current_order_no and trade.order_remark == constants.OrderTypeInit: if self.tradeTarget.status == 0 and trade.order_id == self.tradeTarget.current_order_no and trade.order_remark == constants.OrderTypeInit:
# 此时为建仓成交 # 此时为建仓成交
self.tradeTarget.current_position = int(self.tradeTarget.current_position) + trade.traded_volume # 当前持仓数,账户原有持仓不在策略范围内 # type: ignore self.tradeTarget.current_position = int(self.tradeTarget.current_position) + trade.traded_volume # 当前持仓数,账户原有持仓不在策略范围内 # type: ignore
self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore
self.tradeTarget.grid_index = 1 # type: ignore self.tradeTarget.grid_index = 1 # type: ignore
self.tradeTarget.plan_buy_price = float(config.grid_price[2]) # type: ignore
self.tradeTarget.plan_sell_price = float(config.grid_price[0]) # type: ignore
self.tradeTarget.status = 1 # type: ignore self.tradeTarget.status = 1 # type: ignore
self.saveProxy() type = "建初始仓"
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓订单ID: {self.tradeTarget.current_order_no}已成交 ")
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}')
print(f' 当前持仓: {self.tradeTarget.current_position}')
print(f' 网格坐标: {self.tradeTarget.grid_index}')
elif trade.order_id == self.tradeTarget.current_order_no and self.tradeTarget.status == 1 and trade.order_type == xtconstant.STOCK_SELL: # type: ignore elif trade.order_id == self.tradeTarget.current_order_no and self.tradeTarget.status == 1 and trade.order_type == xtconstant.STOCK_SELL: # type: ignore
# 上涨一格:此时空单成交 # 上涨一格:此时空单成交
self.tradeTarget.current_position = int(self.tradeTarget.current_position) - trade.traded_volume # type: ignore self.tradeTarget.current_position = int(self.tradeTarget.current_position) - trade.traded_volume # type: ignore
self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore
self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) - 1 # type: ignore self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) - 1 # type: ignore
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 上涨 卖单已成交 订单ID: {self.tradeTarget.current_order_no} Price: {config.grid_price[int(self.tradeTarget.grid_index)]} Volume: {config.grid_volume} 手续费: {trade.commission}\n") # type: ignore type = "上涨一格"
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}')
print(f' 当前持仓: {self.tradeTarget.current_position}')
print(f' 网格坐标: {self.tradeTarget.grid_index}')
elif trade.order_id == self.tradeTarget.current_order_no and self.tradeTarget.status == 1 and trade.order_type == xtconstant.STOCK_BUY: # type: ignore elif trade.order_id == self.tradeTarget.current_order_no and self.tradeTarget.status == 1 and trade.order_type == xtconstant.STOCK_BUY: # type: ignore
# 下跌一格:此时多单成交 # 下跌一格:此时多单成交
self.tradeTarget.current_position = int(self.tradeTarget.current_position) + trade.traded_volume # type: ignore self.tradeTarget.current_position = int(self.tradeTarget.current_position) + trade.traded_volume # type: ignore
self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore
self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) + 1 # type: ignore self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) + 1 # type: ignore
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 下跌 买单已成交 订单ID: {self.tradeTarget.current_order_no} Price: {trade.traded_price} Volume: {config.grid_volume} 手续费: {trade.commission}") type = "下跌一格"
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}')
print(f' 当前持仓: {self.tradeTarget.current_position}')
print(f' 网格坐标: {self.tradeTarget.grid_index}')
else: else:
# 打印订单信息和订单状态 type = "其他异常状态"
print(f'|- 非策略内部订单,或订单状态不满足监控条件 {trade.order_id} {trade.stock_code}-{trade.instrument_name} {trade.commission}')
finally:
self.refreshPlanPrice() self.refreshPlanPrice()
self.printTradeReport(trade, type)
finally:
print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:release lock') print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:release lock')
self.dataUpdateLock.release() self.dataUpdateLock.release()
print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:END') print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:END')
def refreshPlanPrice(self): def printTradeReport(self, trade:XtTrade, type:str):
if self.tradeTarget.status == 0: PrintLog(LogLevel.INFO, f"打印交易报告[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]:START")
self.tradeTarget.grid_index = 1 # type: ignore PrintLog(LogLevel.INFO, f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} {type}: {self.tradeTarget.current_order_no}已成交 ")
PrintLog(LogLevel.INFO, f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}')
PrintLog(LogLevel.INFO, f' 当前持仓: {self.tradeTarget.current_position}')
PrintLog(LogLevel.INFO, f' 网格坐标: {self.tradeTarget.grid_index}')
def refreshPlanPrice(self):
buyIdx = 0
sellIdx= 0
if self.tradeTarget.status == 0: # 未建仓
self.tradeTarget.grid_index = 0 # type: ignore
buyIdx = 1
sellIdx = 0
else:
buyIdx: int = self.tradeTarget.grid_index + 1 # pyright: ignore[reportAssignmentType]
sellIdx: int = self.tradeTarget.grid_index - 1
buyIdx: int = self.tradeTarget.grid_index + 1 # pyright: ignore[reportAssignmentType]
sellIdx: int = self.tradeTarget.grid_index - 1
if self.tradeTarget.grid_index > 0: # 可以下空单 if self.tradeTarget.grid_index > 0: # 可以下空单
self.tradeTarget.plan_sell_price = float(self.tradeTarget.getPriceGrid()[sellIdx]) # pyright: ignore[reportAttributeAccessIssue] self.tradeTarget.plan_sell_price = float(self.tradeTarget.getPriceGrid()[sellIdx]) # pyright: ignore[reportAttributeAccessIssue]
else: else:
self.tradeTarget.plan_sell_price = -1.0 # type: ignore self.tradeTarget.plan_sell_price = -1.0 # type: ignore
if self.tradeTarget.grid_index < len(self.tradeTarget.getPriceGrid()) - 1: if self.tradeTarget.grid_index < len(self.tradeTarget.getPriceGrid()) - 1:
self.tradeTarget.plan_buy_price = float(self.tradeTarget.getPriceGrid()[buyIdx]) # pyright: ignore[reportAttributeAccessIssue] self.tradeTarget.plan_buy_price = float(self.tradeTarget.getPriceGrid()[buyIdx]) # pyright: ignore[reportAttributeAccessIssue]
else: else:
self.tradeTarget.plan_buy_price = -1.0 # pyright: ignore[reportAttributeAccessIssue] self.tradeTarget.plan_buy_price = -1.0 # pyright: ignore[reportAttributeAccessIssue]
self.saveProxy() event_bus.publish(EventTradeTargetUpdate, self.tradeTarget)
def getName(self): def getName(self):
return "SFGRID" return "SFGRID"
+22 -53
View File
@@ -1,7 +1,7 @@
from typing import Any from typing import Any
import tkinter as tk import tkinter as tk
from tkinter import ttk, messagebox, filedialog from tkinter import ttk, messagebox
from datetime import datetime from datetime import datetime
import threading import threading
import time import time
@@ -10,9 +10,6 @@ import core.eventbus as eBus
from core.logger import LogLevel, PrintLog from core.logger import LogLevel, PrintLog
from core.sfgrid import bus_events from core.sfgrid import bus_events
from core.sfgrid.model import SFGridTradeTarget from core.sfgrid.model import SFGridTradeTarget
import configparser
import config
from core.sfgrid.objects import GridFixData
from core.qmt import qmtv from core.qmt import qmtv
from core.sfgrid.sfgrid_strategy import SFGridStrategy from core.sfgrid.sfgrid_strategy import SFGridStrategy
@@ -41,20 +38,9 @@ class TradeTargetUI(ttk.Frame):
def init_trade_target_pool(self): def init_trade_target_pool(self):
results = SFGridTradeTarget.select() results = SFGridTradeTarget.select()
for temp in results: for temp in results:
tradeTarget :SFGridTradeTarget = temp tradeTarget:SFGridTradeTarget = temp
id = tradeTarget.get_id()
status = "新建" if tradeTarget.status == 0 else "已建初始仓"
tradeTarget.current_position = qmtv.getStockPosition(tradeTarget.stock_code) # type: ignore tradeTarget.current_position = qmtv.getStockPosition(tradeTarget.stock_code) # type: ignore
# 计算计划交易价格 self.updateTradeTarget(tradeTarget, True)
if tradeTarget.grid_index > 0:
tradeTarget.plan_buy_price = tradeTarget.getPriceGrid()[tradeTarget.grid_index - 1] # type: ignore
if tradeTarget.grid_index < len(tradeTarget.getPriceGrid()) - 1:
tradeTarget.plan_sell_price = tradeTarget.getPriceGrid()[tradeTarget.grid_index + 1] # type: ignore
tradeTarget.save()
PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {tradeTarget.stock_code}-{tradeTarget.stock_name} 当前持仓: {qmtv.getStockPosition(tradeTarget.stock_code)} 网格索引: {tradeTarget.grid_index} 基准价格 {tradeTarget.getPriceGrid()[tradeTarget.grid_index]} 状态: {status} 启用交易线程: {'自动交易中' if tradeTarget.enabled else '交易已停止'}') # type: ignore
PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {tradeTarget.stock_code}-{tradeTarget.stock_name}: {tradeTarget.plan_buy_price} {tradeTarget.plan_sell_price}') # type: ignore
self.updateTradeTarget(tradeTarget)
PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的') PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的')
@@ -64,18 +50,16 @@ class TradeTargetUI(ttk.Frame):
for stock_code, tickData in data.items(): for stock_code, tickData in data.items():
if stock_code in self.stockCodeIdMap: if stock_code in self.stockCodeIdMap:
id:int = self.stockCodeIdMap[stock_code] id:int = self.stockCodeIdMap[stock_code]
PrintLog(LogLevel.INFO, f'股票代码: {stock_code} in trade pool, 市场数据更新 {tickData["lastPrice"]}') PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {stock_code} in trade pool, 市场数据更新 {tickData["lastPrice"]}')
tradeTarget = self.tradeTargetData[id] tradeTarget = self.tradeTargetData[id]
lastPrice = float("{:.3f}".format(tickData['lastPrice'])) lastPrice = float("{:.3f}".format(tickData['lastPrice']))
tradeTarget.market_price = lastPrice # type: ignore tradeTarget.market_price = lastPrice # type: ignore
self.updateTradeTarget(tradeTarget) self.updateTradeTarget(tradeTarget, False)
stock_controller = self.strategy_ctrl[id]
stock_controller.onDataUpdate(tradeTarget)
else: else:
# 非目标交易,发布市场数据更新事件用于市场监控 # 非目标交易,发布市场数据更新事件用于市场监控
lastPrice = tickData['lastPrice'] lastPrice = tickData['lastPrice']
if lastPrice == 10 or stock_code in self.listening_stock: if lastPrice == 10 or stock_code in self.listening_stock:
PrintLog(LogLevel.INFO, f'股票代码: {stock_code} 监听中, 市场数据更新 {tickData["lastPrice"]}') # PrintLog(LogLevel.INFO, f'股票代码: {stock_code} 监听中, 市场数据更新 {tickData["lastPrice"]}')
# 发布市场数据更新事件用于市场监控 # 发布市场数据更新事件用于市场监控
market_target = SFGridTradeTarget() market_target = SFGridTradeTarget()
market_target.stock_code = stock_code market_target.stock_code = stock_code
@@ -94,11 +78,14 @@ class TradeTargetUI(ttk.Frame):
# 来自策略的数据更新 # 来自策略的数据更新
def onStrategyUpdate(self, target: SFGridTradeTarget): def onStrategyUpdate(self, target: SFGridTradeTarget):
PrintLog(LogLevel.INFO, f'策略更新: {target.stock_code}-{target.stock_name}') id = target.get_id()
self.updateTradeTarget(target) self.tradeTargetData[id] = target
def updateTradeTarget(self, target: SFGridTradeTarget): def updateTradeTarget(self, target: SFGridTradeTarget, save: bool = True):
if save:
target.save()
id = target.get_id() id = target.get_id()
status = "新建" if target.status == 0 else "已建初始仓" status = "新建" if target.status == 0 else "已建初始仓"
PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {target.current_position} 网格索引: {target.grid_index} 基准价格 {target.getPriceGrid()[1]} 状态: {status} 启用交易线程: {'自动交易中' if target.enabled else '交易已停止'}') PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {target.current_position} 网格索引: {target.grid_index} 基准价格 {target.getPriceGrid()[1]} 状态: {status} 启用交易线程: {'自动交易中' if target.enabled else '交易已停止'}')
@@ -109,6 +96,8 @@ class TradeTargetUI(ttk.Frame):
if id not in self.strategy_ctrl: if id not in self.strategy_ctrl:
self.stockCodeIdMap[target.stock_code] = id # type: ignore self.stockCodeIdMap[target.stock_code] = id # type: ignore
self.strategy_ctrl[id] = SFGridStrategy(target) # pyright: ignore[reportArgumentType] self.strategy_ctrl[id] = SFGridStrategy(target) # pyright: ignore[reportArgumentType]
else:
self.strategy_ctrl[id].updateTradeTarget(target)
# UI CREATE # UI CREATE
def create_ui(self): def create_ui(self):
@@ -132,8 +121,9 @@ class TradeTargetUI(ttk.Frame):
command=self.btnHandlerStopSelectedTrade, width=12).pack(side=tk.LEFT, padx=2) command=self.btnHandlerStopSelectedTrade, width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text="🛠 交易设置", ttk.Button(toolbar_frame, text="🛠 交易设置",
command=self.btnHandlerTradeSettings, width=12).pack(side=tk.LEFT, padx=2) command=self.btnHandlerTradeSettings, width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text="🛠 网格修正", ttk.Button(toolbar_frame, text="🛠 网格修正(停用)",
command=self.btnHandlerGridCorrect, width=12).pack(side=tk.LEFT, padx=2) # command=self.btnHandlerGridCorrect,
width=12).pack(side=tk.LEFT, padx=2)
ttk.Button(toolbar_frame, text="▣ 实时监控", ttk.Button(toolbar_frame, text="▣ 实时监控",
command=self.btnHandlerToggleMarketMonitor, width=12).pack(side=tk.RIGHT, padx=2) command=self.btnHandlerToggleMarketMonitor, width=12).pack(side=tk.RIGHT, padx=2)
@@ -698,9 +688,10 @@ class TradeTargetUI(ttk.Frame):
setattr(target, 'grid_volume', grid_volume) setattr(target, 'grid_volume', grid_volume)
setattr(target, 'grid_upper_count', grid_upper_count) setattr(target, 'grid_upper_count', grid_upper_count)
setattr(target, 'grid_lower_count', grid_lower_count) setattr(target, 'grid_lower_count', grid_lower_count)
setattr(target, 'status', 0)
# 保存到数据库 # 更新策略控制器
target.save() self.updateTradeTarget(target, True)
# 关闭窗口 # 关闭窗口
config_window.destroy() config_window.destroy()
@@ -940,26 +931,11 @@ class TradeTargetUI(ttk.Frame):
current_order_type='', current_order_type='',
status=-1 status=-1
) )
new_target.save()
# 更新标的池 # 更新标的池
self.updateTradeTarget(new_target) self.updateTradeTarget(new_target, True)
except Exception as e: except Exception as e:
PrintLog(LogLevel.ERROR, f'新增交易标的失败 {stock_code} {e}') PrintLog(LogLevel.ERROR, f'新增交易标的失败 {stock_code} {e}')
# def update_trade_target_grid(self, data: GridFixData):
# """更新交易标的网格信息"""
# try:
# target = data.tradeTarget
# grid_index = data.grid_index
# # 更新数据库中的网格索引
# target.grid_index = grid_index
# target.save()
# PrintLog(LogLevel.INFO, f"网格修正已应用: {target.stock_code} - {target.stock_name}, 网格索引: {grid_index}")
# except Exception as e:
# PrintLog(LogLevel.ERROR, f"网格修正更新失败: {str(e)}")
# button handlers ============================================================================================= # button handlers =============================================================================================
def btnHandlerGridCorrect(self): def btnHandlerGridCorrect(self):
@@ -1045,16 +1021,9 @@ class TradeTargetUI(ttk.Frame):
id = target.get_id() id = target.get_id()
if id in self.strategy_ctrl: if id in self.strategy_ctrl:
tradeController: SFGridStrategy = self.strategy_ctrl[target.get_id()] tradeController: SFGridStrategy = self.strategy_ctrl[target.get_id()]
tradeTarget = tradeController.enabledTrading(False) tradeController.enabledTrading(False)
orders = qmtv.queryPendingOrder(target.stock_code, tradeController.getName()) # type: ignore
for order in orders:
qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id)
print(f'取消未成交订单 {len(orders)}')
self.tradeTargetData[id] = tradeTarget
else: else:
print(f"标的交易控制器不存在 {target.stock_code} {target.stock_name}\n") print(f"标的交易控制器不存在 {target.stock_code} {target.stock_name}\n")
# self.add_log("INFO", f"已暂停交易: {target.stock_code} - {target.stock_name}")
# messagebox.showinfo("暂停成功", f"已暂停 {target.stock_code} ({target.stock_name}) 的交易")
def btnHandlerDelSelectedTradeTarget(self): def btnHandlerDelSelectedTradeTarget(self):
"""删除选中的交易标的""" """删除选中的交易标的"""
+1 -27
View File
@@ -1,9 +1,5 @@
import config
import xtquant.xtconstant as xtconstant
from xtquant import xtdata, xttrader
from xtquant.xttype import StockAccount, XtOrder, XtPosition
import datetime import datetime
def is_trading_time(): def is_trading_time():
""" """
判断当前时间是否在周一至周五的9:30~11:30或13:00~15:00时间段内 判断当前时间是否在周一至周五的9:30~11:30或13:00~15:00时间段内
@@ -37,25 +33,3 @@ def is_trading_time():
return False return False
def getStockPosition(stock_code: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount):
volume = 0
positions = xt_trader.query_stock_positions(account)
if positions:
for temp in positions:
pos:XtPosition = temp
if pos.stock_code == stock_code:
volume = pos.volume
break
return volume
def minPosition(gridIndex:int):
return config.grid_volume * gridIndex
def queryPendingOrder(stock_code:str, tag: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount) -> list[XtOrder]:
if stock_code == None or tag == None:
return []
orders = xt_trader.query_stock_orders(account)
result = [order for order in orders if order.order_status == xtconstant.ORDER_REPORTED and order.stock_code == stock_code and order.strategy_name == tag]
return result