代码测试与整理
This commit is contained in:
@@ -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
@@ -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]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
if lastPrice <= lowPrice: # 下下方多单
|
|
||||||
orderPrice = lowPrice
|
|
||||||
orderType = xtconstant.STOCK_BUY
|
orderType = xtconstant.STOCK_BUY
|
||||||
orderRemark = OrderTypeBuy
|
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:
|
||||||
elif lastPrice >= highPrice: # 下上方空单
|
# 已启用,已建仓,准备网格空单信息
|
||||||
orderPrice = highPrice
|
PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 准备网格空单信息')
|
||||||
|
orderPrice = self.tradeTarget.plan_sell_price # type: ignore
|
||||||
orderType = xtconstant.STOCK_SELL
|
orderType = xtconstant.STOCK_SELL
|
||||||
orderRemark = OrderTypeSell
|
orderRemark = OrderTypeSell
|
||||||
|
|
||||||
|
PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 下单信息: {orderType}, {orderPrice}, {orderRemark}')
|
||||||
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]
|
buyIdx: int = self.tradeTarget.grid_index + 1 # pyright: ignore[reportAssignmentType]
|
||||||
sellIdx: int = self.tradeTarget.grid_index - 1
|
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
@@ -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,27 +931,12 @@ 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
@@ -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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user