调整下单逻辑,避免超过涨跌停价位无法下单的情况。

This commit is contained in:
2025-11-04 11:52:14 +08:00
parent 9429898077
commit c6d253b293
7 changed files with 109 additions and 54 deletions
+4 -1
View File
@@ -1,6 +1,9 @@
[config] [config]
miniQMTPath=D:\\Programs\\DTQMT\\userdata_mini miniQMTPath=D:\\Programs\\DTQMT\\userdata_mini
; miniQMTPath=D:\\Programs\\DTQMT_MN\\userdata_mini ; 测试账号
grid_price=1.665,1.660,1.655,1.650,1.645,1.640,1.635,1.630,1.625,1.620,1.615 grid_price=1.665,1.660,1.655,1.650,1.645,1.640,1.635,1.630,1.625,1.620,1.615
grid_volume = 100 ; grid_price=11.0,10.0,9.0,8.0,7.0,6.0,5.0,4.0,3.0,2.0,1.0
grid_volume = 200
account_no = '99082560' account_no = '99082560'
; account_no = '89009170' ; 测试账号
max_enabled_targets = 10 max_enabled_targets = 10
+1
View File
@@ -52,6 +52,7 @@ class SFGridController(XtQuantTraderCallback):
self.seq = None self.seq = None
print('- [成功]三疯交易系统初始化完成') print('- [成功]三疯交易系统初始化完成')
self.startMarketData()
def startMarketData(self): def startMarketData(self):
+95 -46
View File
@@ -1,9 +1,12 @@
from re import L
from core import util
from core.strategy_db import TradeTarget from core.strategy_db import TradeTarget
from core.util import is_trading_time, queryPendingOrder from core.util import is_trading_time, queryPendingOrder
from xtquant import xttrader, xtconstant from xtquant import xttrader, xtconstant
from xtquant.xttype import StockAccount, XtOrder, XtOrderResponse, XtTrade from xtquant.xttype import StockAccount, XtOrder, XtOrderResponse, XtTrade
import sfgrid_constants import sfgrid_constants
import threading
class StockTradeController: class StockTradeController:
@@ -13,6 +16,7 @@ class StockTradeController:
self.xt_trader: xttrader.XtQuantTrader = xt_trader self.xt_trader: xttrader.XtQuantTrader = xt_trader
self.account:StockAccount = account self.account:StockAccount = account
self.enabledTrading(enabled) self.enabledTrading(enabled)
self.dataUpdateLock = threading.Lock()
def getName(self): def getName(self):
return "SFGRID" return "SFGRID"
@@ -44,18 +48,68 @@ class StockTradeController:
print(f' |- 仓位检查: 持仓需求充足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}') print(f' |- 仓位检查: 持仓需求充足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}')
else: else:
print(f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}') print(f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}')
if is_trading_time():
self.two_way_order(True, True)
def isEnabled(self) -> bool: def isEnabled(self) -> bool:
return bool(self.tradeTarget.enabled) return bool(self.tradeTarget.enabled)
def onDataUpdate(self, data): def onDataUpdate(self, data):
if self.isEnabled(): if not self.isEnabled():
print(f"\n标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 行情数据更新 {data[self.tradeTarget.stock_code]}") return
self.dataUpdateLock.acquire()
index = self.tradeTarget.grid_index
price = sfgrid_constants.grid_price[int(index)] # pyright: ignore[reportArgumentType]
lowPrice = sfgrid_constants.grid_price[int(index) + 1] # pyright: ignore[reportArgumentType]
highPrice = sfgrid_constants.grid_price[int(index) - 1] # pyright: ignore[reportArgumentType]
lastPrice = float("{:.3f}".format(data[self.tradeTarget.stock_code]['lastPrice']))
print(f"标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 市价: {lastPrice}, 网格序号: {index}, 网格价格: {price}, 计划多单价: {lowPrice}, 计划空单价: {highPrice}")
if lastPrice <= lowPrice: # 下下方多单
orders = queryPendingOrder(str(self.tradeTarget.stock_code), self.getName(), self.xt_trader, self.account)
if len([order for order in orders if order.order_type == xtconstant.STOCK_BUY and order.price == lowPrice]) > 0:
# 已存在未交易的多单
print(f' |- 已存在未交易的多单,不重复下单')
else:
print(f' |- 下网格多单')
self.tradeTarget.current_buy_order_no = self.xt_trader.order_stock_async(
self.account,
str(self.tradeTarget.stock_code),
xtconstant.STOCK_BUY,
sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE,
lowPrice,
self.getName(), # strategy_name
self.tradeTarget.stock_code # remark # type: ignore
)
self.tradeTarget.grid_index = int(index) + 1 # type: ignore
self.tradeTarget.current_buy_price = float(lowPrice) # type: ignore
print(f' |- 下网格多单号 {self.tradeTarget.current_buy_order_no}, 网格基准价 {price}, 下单价 {lowPrice}, 下单量 {sfgrid_constants.grid_volume}')
elif lastPrice == highPrice: # 下上方空单
orders = queryPendingOrder(str(self.tradeTarget.stock_code), self.getName(), self.xt_trader, self.account)
if len([order for order in orders if order.order_type == xtconstant.STOCK_SELL and order.price == highPrice]) > 0:
# 已存在未交易的空单
print(f' |- 已存在未交易的空单,不重复下单')
else:
print(f' |- 下网格空单')
self.tradeTarget.current_sell_order_no = self.xt_trader.order_stock_async(
self.account,
str(self.tradeTarget.stock_code),
xtconstant.STOCK_SELL,
sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE,
highPrice,
self.getName(),
self.tradeTarget.stock_code) # type: ignore
self.tradeTarget.grid_index = int(index) - 1 # type: ignore
self.tradeTarget.current_sell_price = float(highPrice) # type: ignore
print(f' |- 下网格空单号 {self.tradeTarget.current_sell_order_no}, 网格基准价 {price}, 下单价 {highPrice}, 下单量 {sfgrid_constants.grid_volume}')
self.tradeTarget.save()
self.dataUpdateLock.release()
def onAsyncOrderResponse(self, order:XtOrderResponse): def onAsyncOrderResponse(self, order:XtOrderResponse):
self.dataUpdateLock.acquire()
stockCode = order.order_remark stockCode = order.order_remark
orderSeq = order.seq orderSeq = order.seq
if self.tradeTarget.current_buy_order_no == order.seq: if self.tradeTarget.current_buy_order_no == order.seq:
@@ -65,12 +119,12 @@ class StockTradeController:
else: else:
print(f' |- 委托回调: 委托单 {order.order_id} {stockCode} {orderSeq} 不在策略监控范围内') print(f' |- 委托回调: 委托单 {order.order_id} {stockCode} {orderSeq} 不在策略监控范围内')
return return
rc = self.tradeTarget.save() rc = self.tradeTarget.save()
print(f' |- 委托回调: 委托单 {order.order_id} {stockCode} {orderSeq} 处理结果: {rc}') print(f' |- 委托回调: 委托单 {order.order_id} {stockCode} {orderSeq} 处理结果: {rc}')
self.dataUpdateLock.release()
def onOrderTrade(self, trade:XtTrade): def onOrderTrade(self, trade:XtTrade):
indicator = False self.dataUpdateLock.acquire()
if int(self.tradeTarget.status) == 0 and trade.order_id == self.initBuyOrderId : # type: ignore if int(self.tradeTarget.status) == 0 and trade.order_id == self.initBuyOrderId : # 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
@@ -82,7 +136,6 @@ class StockTradeController:
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}')
print(f' 当前持仓: {self.tradeTarget.current_position}') print(f' 当前持仓: {self.tradeTarget.current_position}')
print(f' 网格坐标: {self.tradeTarget.grid_index}') print(f' 网格坐标: {self.tradeTarget.grid_index}')
indicator = True # 双向下单
elif trade.order_id == self.tradeTarget.current_sell_order_no and int(self.tradeTarget.status) == 1: # type: ignore elif trade.order_id == self.tradeTarget.current_sell_order_no and int(self.tradeTarget.status) == 1: # 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
@@ -95,7 +148,6 @@ class StockTradeController:
print(f' 网格坐标: {self.tradeTarget.grid_index}') print(f' 网格坐标: {self.tradeTarget.grid_index}')
cancelResult = self.xt_trader.cancel_order_stock_async(self.account, self.tradeTarget.current_buy_order_no) cancelResult = self.xt_trader.cancel_order_stock_async(self.account, self.tradeTarget.current_buy_order_no)
print(f' 上涨一格,空单成交,对侧买单已撤单 cancelResult: {cancelResult > 0}') print(f' 上涨一格,空单成交,对侧买单已撤单 cancelResult: {cancelResult > 0}')
indicator = True # 双向下单
elif trade.order_id == self.tradeTarget.current_buy_order_no and int(self.tradeTarget.status) == 1: # type: ignore elif trade.order_id == self.tradeTarget.current_buy_order_no and int(self.tradeTarget.status) == 1: # 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
@@ -108,14 +160,11 @@ class StockTradeController:
print(f' 网格坐标: {self.tradeTarget.grid_index}') print(f' 网格坐标: {self.tradeTarget.grid_index}')
cancelResult = self.xt_trader.cancel_order_stock_async(self.account, self.tradeTarget.current_sell_order_no) cancelResult = self.xt_trader.cancel_order_stock_async(self.account, self.tradeTarget.current_sell_order_no)
print(f' 下跌一格,多单成交,对侧卖单已撤单 cancelResult: {cancelResult > 0}') print(f' 下跌一格,多单成交,对侧卖单已撤单 cancelResult: {cancelResult > 0}')
indicator = True # 双向下单
else: else:
# 打印订单信息和订单状态 # 打印订单信息和订单状态
print(f'|- 非策略内部订单,或订单状态不满足监控条件 {trade.order_id} {trade.stock_code}-{trade.instrument_name} {trade.commission}') print(f'|- 非策略内部订单,或订单状态不满足监控条件 {trade.order_id} {trade.stock_code}-{trade.instrument_name} {trade.commission}')
if indicator and self.isEnabled() and is_trading_time(): self.dataUpdateLock.release()
print(f'goto two way order')
self.two_way_order(True, True) # 双向下单
# Description: 新标的,建基础仓 # Description: 新标的,建基础仓
@@ -132,37 +181,37 @@ class StockTradeController:
# Description: 网格跳格,双向下单 # Description: 网格跳格,双向下单
def two_way_order(self, buy, sell): # def two_way_order(self, buy, sell):
print(f'|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 网格跳格,双向下单') # print(f'|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 网格跳格,双向下单')
print(f' |- 网格坐标: {self.tradeTarget.grid_index}, buy:{buy}, sell:{sell}') # print(f' |- 网格坐标: {self.tradeTarget.grid_index}, buy:{buy}, sell:{sell}')
if buy and int(self.tradeTarget.grid_index)+1 < len(sfgrid_constants.grid_price): # 价格没有超过网格下边界,可以下多单 # type: ignore # if buy and int(self.tradeTarget.grid_index)+1 < len(sfgrid_constants.grid_price): # 价格没有超过网格下边界,可以下多单 # type: ignore
currentPrice = sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)] # type: ignore # currentPrice = sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)] # type: ignore
buyPrice = sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)+1] # type: ignore # buyPrice = sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)+1] # type: ignore
self.tradeTarget.current_buy_order_no = self.xt_trader.order_stock_async( # self.tradeTarget.current_buy_order_no = self.xt_trader.order_stock_async(
self.account, # self.account,
str(self.tradeTarget.stock_code), # str(self.tradeTarget.stock_code),
xtconstant.STOCK_BUY, # xtconstant.STOCK_BUY,
sfgrid_constants.grid_volume, # sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE, # xtconstant.FIX_PRICE,
buyPrice, # buyPrice,
self.getName(), # strategy_name # self.getName(), # strategy_name
self.tradeTarget.stock_code # remark # type: ignore # self.tradeTarget.stock_code # remark # type: ignore
) # )
self.tradeTarget.current_buy_price = float(buyPrice) # type: ignore # self.tradeTarget.current_buy_price = float(buyPrice) # type: ignore
print(f' |- 下网格多单 OrderId {self.tradeTarget.current_buy_order_no}, 网格基准价 {currentPrice}, 下单价 {buyPrice}, 下单量 {sfgrid_constants.grid_volume}') # print(f' |- 下网格多单 OrderId {self.tradeTarget.current_buy_order_no}, 网格基准价 {currentPrice}, 下单价 {buyPrice}, 下单量 {sfgrid_constants.grid_volume}')
if sell and int(self.tradeTarget.grid_index)-1 >=0: # 价格没有超过网格上边界,可以下空单 # type: ignore # if sell and int(self.tradeTarget.grid_index)-1 >=0: # 价格没有超过网格上边界,可以下空单 # type: ignore
currentPrice = sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)] # type: ignore # currentPrice = sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)] # type: ignore
sellPrice = sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)-1] # type: ignore # sellPrice = sfgrid_constants.grid_price[int(self.tradeTarget.grid_index)-1] # type: ignore
self.tradeTarget.current_sell_order_no = self.xt_trader.order_stock_async( # self.tradeTarget.current_sell_order_no = self.xt_trader.order_stock_async(
self.account, # self.account,
str(self.tradeTarget.stock_code), # str(self.tradeTarget.stock_code),
xtconstant.STOCK_SELL, # xtconstant.STOCK_SELL,
sfgrid_constants.grid_volume, # sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE, # xtconstant.FIX_PRICE,
sellPrice, # sellPrice,
self.getName(), # self.getName(),
self.tradeTarget.stock_code) # type: ignore # self.tradeTarget.stock_code) # type: ignore
self.tradeTarget.current_sell_price = float(sellPrice) # type: ignore # self.tradeTarget.current_sell_price = float(sellPrice) # type: ignore
print(f' |- 下网格空单 OrderId {self.tradeTarget.current_sell_order_no}, 网格基准价 {currentPrice}, 下单价 {sellPrice}, 下单量 {sfgrid_constants.grid_volume}') # print(f' |- 下网格空单 OrderId {self.tradeTarget.current_sell_order_no}, 网格基准价 {currentPrice}, 下单价 {sellPrice}, 下单量 {sfgrid_constants.grid_volume}')
self.tradeTarget.save() # self.tradeTarget.save()
+5 -2
View File
@@ -1,7 +1,10 @@
from typing import Any
import sfgrid_constants import sfgrid_constants
import xtquant.xtconstant as xtconstant import xtquant.xtconstant as xtconstant
from xtquant import xtdata, xttrader from xtquant import xtdata, xttrader
from xtquant.xttype import StockAccount, XtPosition from xtquant.xttype import StockAccount, XtOrder, XtPosition
import datetime import datetime
def is_trading_time(): def is_trading_time():
@@ -58,7 +61,7 @@ def getStockPosition(stock_code: str, xt_trader: xttrader.XtQuantTrader, account
def minPosition(gridIndex:int): def minPosition(gridIndex:int):
return sfgrid_constants.grid_volume * gridIndex return sfgrid_constants.grid_volume * gridIndex
def queryPendingOrder(stock_code:str, tag: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount): def queryPendingOrder(stock_code:str, tag: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount) -> list[XtOrder]:
if stock_code == None or tag == None: if stock_code == None or tag == None:
return [] return []
orders = xt_trader.query_stock_orders(account) orders = xt_trader.query_stock_orders(account)
BIN
View File
Binary file not shown.
+4 -4
View File
@@ -2,13 +2,13 @@ from typing import List
import configparser import configparser
# miniQMTPath = r'D:\\Programs\\DTQMT_MN\\userdata_mini' # miniQMT软件的安装路径 # miniQMTPath = r'D:\\Programs\\DTQMT_MN\\userdata_mini' # miniQMT软件的安装路径
# miniQMTPath = r'D:\\Programs\\DTQMT\\userdata_mini' # miniQMT软件的安装路径 miniQMTPath = r'D:\\Programs\\DTQMT\\userdata_mini' # miniQMT软件的安装路径
# miniQMTPath = '' # miniQMTPath = ''
# grid_price = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 网格价格设置,从高到低 # grid_price = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 网格价格设置,从高到低
grid_price:List[float] = [] # 网格价格设置,从高到低 grid_price:List[float] = [] # 网格价格设置,从高到低
grid_volume:int = 100 # 每个网格的交易手数 grid_volume:int = 100 # 每个网格的交易手数
# account_no:str = '99082560' account_no:str = '99082560'
# account_no = '89009170' # 交易账号 # account_no:str = '89009170' # 交易账号
max_enabled_targets:int = 10 max_enabled_targets:int = 10
def initConfig(): def initConfig():
@@ -21,7 +21,7 @@ def initConfig():
grid_price = [float(item) for item in str_list] grid_price = [float(item) for item in str_list]
print(f'网格设置:{grid_price}') print(f'网格设置:{grid_price}')
grid_volume = config.getint('config','grid_volume') grid_volume = config.getint('config','grid_volume')
account_no = config.get('config','account_no') # account_no = config.get('config','account_no')
print(f'账号: {account_no}') print(f'账号: {account_no}')
max_enabled_targets = config.getint('config','max_enabled_targets') max_enabled_targets = config.getint('config','max_enabled_targets')
print(f'最大启用目标数: {max_enabled_targets}') print(f'最大启用目标数: {max_enabled_targets}')
-1
View File
@@ -43,7 +43,6 @@ def pauseTrade(index:int):
def stockTradeCtrl(index: int): def stockTradeCtrl(index: int):
return ctrl.stock_trade_ctrl[ctrl.instrument_pool[index].stock_code] return ctrl.stock_trade_ctrl[ctrl.instrument_pool[index].stock_code]
def help(): def help():
print("基础指令:") print("基础指令:")
print(" ===================================================") print(" ===================================================")