实现策略核心交易逻辑

This commit is contained in:
2025-10-29 15:26:34 +08:00
parent c928b79c83
commit 3f5fc02667
6 changed files with 159 additions and 54 deletions
BIN
View File
Binary file not shown.
+40 -13
View File
@@ -1,12 +1,15 @@
# coding:utf-8
from os import popen
import time, sys
from peewee import ModelSelect
sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8
import strategy_db
import sfgrid_constants
from sfgrid_trade_controller import StockTradeController
from util import getInstrumentName, getStockPosition
from xtquant.xttrader import XtQuantTrader
from xtquant.xttype import StockAccount, XtOrder
from xtquant.xttype import StockAccount, XtOrder, XtTrade
from xtquant import xtdata
from xtquant.xttrader import XtQuantTraderCallback
import datetime
@@ -51,7 +54,9 @@ class SFGridController(XtQuantTraderCallback):
grid_index=0,
last_trade_price=0.0,
current_buy_price=0.0,
current_sell_price=0.0
current_buy_order_no='',
current_sell_price=0.0,
current_sell_order_no=''
)
new_target.save()
print(f'新增交易标的 {stock_code} {stock_name}, {new_target.id}')
@@ -59,13 +64,21 @@ class SFGridController(XtQuantTraderCallback):
pos = getStockPosition(stock_code, self.xt_trader, self.account)
strategy_db.TradeTarget.update(current_position=pos).where(strategy_db.TradeTarget.stock_code == stock_code).execute()
# 更新标的池
self.instrument_pool = strategy_db.TradeTarget.select()
self.refresh_targets()
# 添加交易控制器
stockTradeController = StockTradeController(new_target, self.xt_trader, self.account, new_target.enabled)
self.stock_trade_ctrl[stock_code] = stockTradeController
except Exception as e:
print(f'新增交易标的失败 {stock_code} {e}')
def del_trade_target(self, index:int):
target: strategy_db.TradeTarget = self.instrument_pool[index]
# self.stock_trade_ctrl.
del self.stock_trade_ctrl[target.stock_code]
target.delete_instance()
self.refresh_targets()
def init_trader(self, path):
session_id = int(time.time())
@@ -79,14 +92,20 @@ class SFGridController(XtQuantTraderCallback):
self.account= StockAccount(account_id, account_type)
print(f'- 交易账号对象初始化完成, 账号: {self.account.account_id}')
def init_instrument_pool(self):
self.instrument_pool = strategy_db.TradeTarget.select()
self.refresh_targets()
for tradeTarget in self.instrument_pool:
stockTradeController = StockTradeController(tradeTarget, self.xt_trader, self.account, tradeTarget.enabled)
self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController
print(f'- 初始化标的池初始化完成 , 共 {len(self.instrument_pool)} 个标的')
def refresh_targets(self):
# 更新标的池
self.instrument_pool:ModelSelect = strategy_db.TradeTarget.select()
self.print_pool()
def print_pool(self):
@@ -170,19 +189,26 @@ class SFGridController(XtQuantTraderCallback):
# ====== 市场回调方法 -- 以下方法由XtQuantData调用 ======
def onDataUpdate(self, data):
# 遍历股池
# for stock_code, data in data.items():
# if data['lastPrice'] == 10.0:
# print(f'target = {stock_code} - {getInstrumentName(stock_code)} {data['lastPrice']}')
# self.add_trade_target(stock_code)
# self.stock_trade_ctrl[stock_code].enabledTrading(True)
# if stock_code not in self.stock_trade_ctrl:
# self.add_trade_target(stock_code)
# self.stock_trade_ctrl[stock_code].onDataUpdate(data)
for target in self.instrument_pool:
stock_code = target.stock_code
# 如果存在对应的StockTradeController,则调用其onDataUpdate方法
if stock_code not in self.stock_trade_ctrl:
print(f"股票代码 {stock_code} 未在交易控制器中找到,跳过处理。\n")
continue
if stock_code not in data:
print(f"股票代码 {stock_code} 未在行情数据中找到,跳过处理。\n")
if stock_code not in self.stock_trade_ctrl or stock_code not in data:
# print(f"股票代码 {stock_code} 未在交易控制器中找到,跳过处理。\n")
continue
stock_controller: StockTradeController = self.stock_trade_ctrl[stock_code]
stock_controller.onDataUpdate(data)
# ====== 市场回调方法 -- 以下方法由XtQuantTrader调用 ======
def on_connected(self):
"""
@@ -205,11 +231,12 @@ class SFGridController(XtQuantTraderCallback):
"""
stockCode = order.stock_code
# 如果存在对应的StockTradeController,则调用其onDataUpdate方法
if stockCode not in self.stock_trade_ctrl:
self.stock_trade_ctrl[stockCode].onOrderUpdate(order)
if stockCode in self.stock_trade_ctrl:
ctrl:StockTradeController = self.stock_trade_ctrl[stockCode]
ctrl.onOrderUpdate(order)
print(datetime.datetime.now(), '委托回调 投资备注', order.order_remark)
def on_stock_trade(self, trade):
def on_stock_trade(self, trade:XtTrade):
"""
成交变动推送
:param trade: XtTrade对象
+7 -3
View File
@@ -1,4 +1,8 @@
miniQMTPath = r'D:\\Programs\\DTQMT\\userdata_mini' # miniQMT软件的安装路径
grid_price = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 网格价格设置,从高到低
miniQMTPath = r'D:\\Programs\\DTQMT_MN\\userdata_mini' # miniQMT软件的安装路径
# D:\Programs\DTQMT_MN\userdata_mini
# grid_price = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 网格价格设置,从高到低
grid_price = [10.1, 10.00, 9.9, 9.8, 9.7, 9.6, 9.5, 9.4, 9.3, 9.2, 9.1] # 网格价格设置,从高到低
grid_volume = 100 # 每个网格的交易手数
account_no = '99082560' # 交易账号
# account_no = '99082560'
account_no = '89009170' # 交易账号
max_enabled_targets = 10
+82 -20
View File
@@ -3,7 +3,7 @@ import strategy_db
from util import getInstrumentName, getStockPosition
from xtquant import xttrader, xtdata, xtconstant
from xtquant.xttype import StockAccount, XtOrder
from xtquant.xttype import StockAccount, XtOrder, XtTrade
import sfgrid_constants
@@ -14,7 +14,6 @@ class StockTradeController:
self.xt_trader = xt_trader
self.account = account
self.currentPosition = getStockPosition(self.tradeTarget.stock_code, self.xt_trader, self.account)
self.tradeRecords = strategy_db.TradeRecord.select().where(strategy_db.TradeRecord.stock_code == self.tradeTarget.stock_code).order_by(strategy_db.TradeRecord.trade_time.desc())
def enabledTrading(self, enabled: bool):
@@ -28,14 +27,7 @@ class StockTradeController:
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓 买单准备中...\n")
self.tradeTarget.grid_index = 1
self.tradeTarget.save()
self.initBuyOrderId = self.xt_trader.order_stock(
self.account,
self.tradeTarget.stock_code,
xtconstant.STOCK_BUY,
sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE,
sfgrid_constants.grid_price[self.tradeTarget.grid_index],
'sf_grid', f'{self.tradeTarget.stock_code}_init_buy')
self.init_stock_position()
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓 买单已发出 InitBuyOrderId: {self.initBuyOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume}\n")
else:
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 已有仓位或非初始状态 无需建初始仓 当前仓位: {self.tradeTarget.current_position} 状态: {self.tradeTarget.status}\n")
@@ -46,21 +38,91 @@ class StockTradeController:
def onDataUpdate(self, data):
if self.isEnabled():
print(f"标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 行情数据更新 {data[self.tradeTarget.stock_code]}\n")
print(f"\n标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 行情数据更新 {data[self.tradeTarget.stock_code]}")
def onOrderUpdate(self, order:XtOrder):
pass
def onOrderTrade(self, trade:XtTrade):
indicator = False
if trade.order_id == self.initBuyOrderId and self.tradeTarget.status == 0:
# 此时为建仓成交
self.tradeTarget.current_position += sfgrid_constants.grid_volume # 当前持仓数,账户原有持仓不在策略范围内
self.tradeTarget.last_trade_price = trade.traded_price
self.tradeTarget.grid_index = 1
self.tradeTarget.status = 1
self.tradeTarget.save()
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓订单ID: {self.initBuyOrderId}已成交 \n")
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}\n')
print(f' 当前持仓: {self.tradeTarget.current_position}\n')
print(f' 网格坐标: {self.tradeTarget.grid_index}\n')
indicator = True # 双向下单
elif trade.order_id == self.sellOrderId and self.tradeTarget.status == 1:
# 上涨一格:此时空单成交
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 上涨 卖单已成交 订单ID: {self.sellOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}\n")
self.tradeTarget.current_position = -sfgrid_constants.grid_volume
self.tradeTarget.last_trade_price = trade.traded_price
self.tradeTarget.grid_index += 1
self.tradeTarget.save()
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 上涨 卖单已成交 订单ID: {self.sellOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}\n")
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}\n')
print(f' 当前持仓: {self.tradeTarget.current_position}\n')
print(f' 网格坐标: {self.tradeTarget.grid_index}\n')
indicator = True # 双向下单
elif trade.order_id == self.buyOrderId and self.tradeTarget.status == 1:
# 下跌一格:此时多单成交
self.tradeTarget.current_position = +sfgrid_constants.grid_volume
self.tradeTarget.last_trade_price = trade.traded_price
self.tradeTarget.grid_index -= 1
self.tradeTarget.save()
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 下跌 买单已成交 订单ID: {self.buyOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume} 手续费: {trade.commission}\n")
print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}\n')
print(f' 当前持仓: {self.tradeTarget.current_position}\n')
print(f' 网格坐标: {self.tradeTarget.grid_index}\n')
indicator = True # 双向下单
else:
# 打印订单信息和订单状态
print(f'非策略内部订单,或订单状态不满足监控条件 {trade.order_id} {trade.stock_code}-{trade.instrument_name} {trade.commission}')
# Description: 程序启动后
def check_stock_position(self):
volume = getStockPosition(self.tradeTarget.stock_code, self.xt_trader, self.account)
pass
if indicator and self.isEnabled():
self.two_way_order() # 双向下单
# Description: 新标的,建基础仓
def init_stock_position(self):
pass
self.initBuyOrderId = self.xt_trader.order_stock(
self.account,
self.tradeTarget.stock_code,
xtconstant.STOCK_BUY,
sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE,
sfgrid_constants.grid_price[self.tradeTarget.grid_index],
'sf_grid', f'{self.tradeTarget.stock_code}_init_buy')
print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓 买单已发出 InitBuyOrderId: {self.initBuyOrderId} Price: {sfgrid_constants.grid_price[self.tradeTarget.grid_index]} Volume: {sfgrid_constants.grid_volume}\n")
# Description: 双向下单
# Description: 网格跳格,双向下单
def two_way_order(self):
pass
if self.tradeTarget.grid_index+1 < len(sfgrid_constants.grid_price): # 价格没有超过网格下边界,可以下多单
currentPrice = sfgrid_constants.grid_price[self.tradeTarget.grid_index]
buyPrice = sfgrid_constants.grid_price[self.tradeTarget.grid_index+1]
self.buyOrderId = self.xt_trader.order_stock(
self.account,
self.tradeTarget.stock_code,
xtconstant.STOCK_BUY,
sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE,
buyPrice,
'sf_grid', f'{self.tradeTarget.stock_code}_grid_down_{self.tradeTarget.grid_index}_{currentPrice}_{buyPrice}')
self.tradeTarget.current_buy_price = buyPrice
if self.tradeTarget.grid_index-1 >=0: # 价格没有超过网格上边界,可以下空单
currentPrice = sfgrid_constants.grid_price[self.tradeTarget.grid_index]
sellPrice = sfgrid_constants.grid_price[self.tradeTarget.grid_index-1]
self.sellOrderId = self.xt_trader.order_stock(
self.account,
self.tradeTarget.stock_code,
xtconstant.STOCK_SELL,
sfgrid_constants.grid_volume,
xtconstant.FIX_PRICE,
sellPrice,
'sf_grid', f'{self.tradeTarget.stock_code}_grid_up_{self.tradeTarget.grid_index}_{currentPrice}_{sellPrice}')
self.tradeTarget.current_sell_price = sellPrice
self.tradeTarget.save()
+27 -10
View File
@@ -1,5 +1,7 @@
# coding:utf-8
import sys
import csv
import chardet
import sfgrid_constants
sys.stdout.reconfigure(encoding='utf-8') # 设置标准输出编码为UTF-8
@@ -18,12 +20,15 @@ def startMarketData():
def stopMarketData():
ctrl.stopMarketData()
def targets():
def pool():
ctrl.print_pool()
def addTradeTarget(stock_code):
def addTarget(stock_code):
ctrl.add_trade_target(stock_code)
def delTarget(index:int):
ctrl.del_trade_target(index)
def accountInfo():
ctrl.print_account_info()
@@ -39,19 +44,31 @@ def pauseTrade(index:int):
def stockTradeCtrl(index: int):
return ctrl.stock_trade_ctrl[ctrl.instrument_pool[index].stock_code]
def importCsv(path:str):
with open(path, 'r', encoding='utf-8', errors='replace') as infile:
result = chardet.detect(infile)
print(result['encoding'])
# reader = csv.reader(infile)
# data = [row for row in reader]
# print(data)
def help():
print("可用命令:")
print("基础指令:")
print(" ===================================================")
print(" startMarketData() - 启动市场数据接收")
print(" stopMarketData() - 停止市场数据接收")
print(" addTradeTarget(stock_code) - 添加交易标的")
print(" stopMarketData() - 停止市场数据接收\n")
print(" pool() - 打印标的池信息")
print(" addTarget(stock_code) - 添加交易标的")
print(" delTarget(index) - 删除交易标的\n")
print(" accountInfo() - 打印账户信息")
print(" positionInfo() - 打印持仓信息")
print(" targets() - 打印标的池信息")
print(" startTrade(index) - 启动标的交易线程")
print(" pauseTrade(index) - 暂停标的交易线程")
print(" stockTradeCtrl(index) - 获取标的交易控制器")
print(" positionInfo() - 打印持仓信息\n")
print(" startTrade(index) - 启动标的交易")
print(" pauseTrade(index) - 暂停标的交易")
print(" importCsv(path) - 导入CSV文件")
print(" ===================================================")
print("内部指令:")
print(" stockTradeCtrl(index) - 获取标的交易控制器")
print(" ctrl - 访问控制器实例")
if __name__ == '__main__':
+3 -8
View File
@@ -16,13 +16,8 @@ class TradeTarget(BaseModel):
grid_index = IntegerField()
last_trade_price = FloatField()
current_buy_price = FloatField()
current_buy_order_no = CharField(default='')
current_sell_price = FloatField()
status = IntegerField(default=0) # 0表示新建,1表示已建初始仓
current_sell_order_no = CharField(default='')
status = IntegerField(default=0) # 0表示新标的,1表示已建初始仓,正常交易中
enabled = BooleanField(default=False) # 是否启动交易线程
class TradeRecord(BaseModel):
stock_code = CharField()
trade_type = CharField() # 'buy' 或 'sell'
price = FloatField()
volume = IntegerField()
trade_time = CharField() # 可以存储为字符串格式的时间