"""
|
交易方式模块(总览处理所有渠道的各种交易方法集合)
|
"""
|
import multiprocessing
|
import threading
|
|
# import log
|
from strategy import data_cache
|
import data_server
|
from log_module.log import logger_debug
|
|
# import account_management
|
# 引入日志模块
|
from strategy.logging_config import get_logger
|
from trade import huaxin_trade_api, huaxin_trade_data_update, middle_api_protocol
|
from utils import huaxin_util
|
|
# 获取logger实例
|
logger = get_logger()
|
|
|
# 下单买入函数(按金额,以限价买)【按金额买 基础版】
|
def buy_order_by_value(symbol, buy_order_value, sec_name, price):
|
price = round(float(price), 2)
|
volume = (int(buy_order_value / price) // 100) * 100
|
order = huaxin_trade_api.order(1, symbol[-6:], volume, price, blocking=True)
|
logger.info(f"order===={order}")
|
logger.info(f"买票 执行成功:【{sec_name}】")
|
# 买票后添加 持仓代码集合
|
data_cache.position_symbols_set.add(symbol)
|
# 买票后添加 今日新增持仓代码集合
|
data_cache.addition_position_symbols_set.add(symbol)
|
logger.info(f"当前持仓数量:::{len(data_cache.position_symbols_set)}")
|
logger.info(f"今日新增持仓数量:::{len(data_cache.addition_position_symbols_set)}")
|
|
|
# 下单买入函数(按可用资金的一定比例,在涨停价买)【按金额买 高级版】
|
def buy_order_by_part_value(part_of_value, symbol, available, today_limit_up_price, sec_name, index):
|
"""
|
:param symbol: 代码
|
:param available: 可用资金
|
:param part_of_value: 计划委买 账户余额的 比例
|
:param today_limit_up_price: 今日涨停价
|
:param sec_name: 公司名称
|
:param index: 持仓对象列表中的个股对应序列号
|
:return: 尝试返回的订单数据
|
"""
|
logger.info(f"当前账户可用资金available==={available}")
|
buy_order_value = round(available * part_of_value, 2)
|
logger.info(f"当前计划比例==={part_of_value},当前委托金额==={buy_order_value}")
|
# 只有持仓数量大于委卖数量才进入买票流程
|
if available >= buy_order_value:
|
sell_order_by_volume(symbol, buy_order_value, sec_name, today_limit_up_price)
|
logger.info(f"【十分之{part_of_value * 10}可用资金】委买完毕,默认成功")
|
data_cache.available = available - buy_order_value
|
logger.info(f"买票执行成功:【{sec_name}】")
|
logger.info(f"买票后剩余资金:{round(data_cache.available, 2)}")
|
else:
|
logger.info(f"【{sec_name}】,持仓:{available}小于计划委托:{part_of_value},委托失败!")
|
|
|
# 下单卖出函数(按持仓数量,在限价卖)【按量卖 基础版】
|
def sell_order_by_volume(symbol, volume, sec_name, price):
|
price = round(float(price), 2)
|
order = huaxin_trade_api.order(2, symbol[-6:], volume, price, blocking=True)
|
logger.info(f"order===={order}")
|
# order_test = [
|
# {'strategy_id': '507bb60a-a919-11ee-b6ad-0ae0afd621cd',
|
# 'account_id': 'aaee2221-839c-11ee-a7cd-00163e022aa6',
|
# 'account_name': 'aaee2221-839c-11ee-a7cd-00163e022aa6',
|
# 'cl_ord_id': '4a8fff26-7ba6-11ef-8351-00e070c692a6',
|
# 'symbol': 'SHSE.600716',
|
# 'side': 2,
|
# 'position_effect': 2,
|
# 'order_type': 1,
|
# 'status': 10,
|
# 'price': 2.62,
|
# 'order_style': 1,
|
# 'volume': 3200,
|
# 'created_at': datetime.datetime(2024, 9, 26, 9, 26, 1, 751325, tzinfo=datetime.timezone(
|
# datetime.timedelta(seconds=28800),
|
# 'Asia/Shanghai')),
|
# 'order_business': 2,
|
# 'properties': {'board': '1', 'origin_product': 'MYQUANT', 'origin_module': 'API', 'sec_type': '1'},
|
# 'order_id': '',
|
# 'ex_ord_id': '',
|
# 'algo_order_id': '',
|
# 'position_side': 0,
|
# 'order_duration': 0,
|
# 'order_qualifier': 0,
|
# 'order_src': 0,
|
# 'position_src': 0,
|
# 'ord_rej_reason': 0,
|
# 'ord_rej_reason_detail': '',
|
# 'stop_price': 0.0,
|
# 'value': 0.0,
|
# 'percent': 0.0,
|
# 'target_volume': 0,
|
# 'target_value': 0.0,
|
# 'target_percent': 0.0,
|
# 'filled_volume': 0,
|
# 'filled_vwap': 0.0,
|
# 'filled_amount': 0.0,
|
# 'filled_commission': 0.0,
|
# 'updated_at': None}]
|
logger.info(f"策略ID===={order[0]['strategy_id']}")
|
logger.info(f"账号ID===={order[0]['account_id']}")
|
logger.info(f"账户登录名===={order[0]['account_name']}")
|
logger.info(f"委托客户端ID,下单生成,固定不变(掘金维护,下单唯一标识)===={order[0]['cl_ord_id']}")
|
|
logger.info(f"标的代码===={order[0]['symbol']}")
|
logger.info(f"买卖方向===={order[0]['side']}")
|
logger.info(f"开平标志===={order[0]['position_effect']}")
|
logger.info(f"委托类型===={order[0]['order_type']}")
|
logger.info(f"委托状态===={order[0]['status']} ")
|
logger.info(f"委托价格===={order[0]['price']}")
|
logger.info(f"委托风格===={order[0]['order_style']}")
|
logger.info(f"委托量===={order[0]['volume']}")
|
logger.info(f"委托业务属性===={order[0]['order_business']}")
|
|
logger.info(f"财产===={order[0]['properties']}")
|
|
# logger.info(f"委托柜台ID(系统字段,下单不会立刻生成,委托报到柜台才会生成)===={order[0]['order_id']}")
|
# logger.info(f"委托交易所ID(系统字段,下单不会立刻生成,委托报到柜台才会生成)===={order[0]['ex_ord_id']}")
|
# logger.info(f"算法单ID===={order[0]['algo_order_id']}")
|
|
logger.info(f"持仓方向===={order[0]['position_side']}")
|
logger.info(f"委托时间属性===={order[0]['order_duration']}")
|
logger.info(f"委托成交属性===={order[0]['order_qualifier']}")
|
logger.info(f"order_src===={order[0]['order_src']}")
|
logger.info(f"头寸来源(系统字段)===={order[0]['position_src']}")
|
logger.info(f"委托拒绝原因===={order[0]['ord_rej_reason']}")
|
logger.info(f"委托拒绝原因描述===={order[0]['ord_rej_reason_detail']}")
|
logger.info(f"stop_price===={order[0]['stop_price']}")
|
logger.info(f"委托额===={order[0]['value']}")
|
logger.info(f"委托百分比===={order[0]['percent']}")
|
logger.info(f"委托目标量===={order[0]['target_volume']}")
|
logger.info(f"委托目标额===={order[0]['target_value']}")
|
logger.info(f"委托目标百分比===={order[0]['target_percent']}")
|
logger.info(f"已成量 (一笔委托对应多笔成交为累计值)===={order[0]['filled_volume']}")
|
logger.info(
|
f"已成均价,公式为(price*(1+backtest_slippage_ratio)) (仅股票实盘支持,期货实盘不支持)===={order[0]['filled_vwap']}")
|
logger.info(
|
f"已成金额,公式为(filled_volume*filled_vwap) (仅股票实盘支持,期货实盘不支持)===={order[0]['filled_amount']}")
|
logger.info(f"filled_commission===={order[0]['filled_commission']}")
|
|
logger.info(f"委托更新时间===={order[0]['updated_at']}")
|
logger.info(f"委托创建时间===={order[0]['created_at']}")
|
|
logger.info(f"卖票 执行成功:【{sec_name}】")
|
|
|
# 下单卖出函数(按持仓数量的一定比例,在跌停价卖)【按量卖 高级版】
|
def sell_order_by_part_volume(part_of_volume, symbol, position_volume_yesterday, today_limit_down_price, sec_name,
|
index):
|
"""
|
:param symbol: 代码
|
:param position_volume_yesterday: 可用持仓数量
|
:param part_of_volume: 计划委卖持仓量的比例
|
:param today_limit_down_price: 今日跌停价
|
:param sec_name: 公司名称
|
:param index: 持仓对象列表中的个股对应序列号
|
:return: 尝试返回的订单数据
|
"""
|
logger.info(f"当前个股持仓手数==={position_volume_yesterday}")
|
# sell_order_volume = int(position_volume_yesterday * part_of_volume)
|
sell_order_volume = round(position_volume_yesterday * part_of_volume / 100) * 100
|
logger.info(f"当前计划比例==={part_of_volume},当前委托量==={sell_order_volume}")
|
# 当委托量大于0
|
if sell_order_volume > 0:
|
# 只有持仓数量大于委卖数量才进入买票流程
|
if position_volume_yesterday >= sell_order_volume:
|
sell_order_by_volume(symbol, sell_order_volume, sec_name, today_limit_down_price)
|
logger.info(f"【十分之 {round(part_of_volume * 10)} 仓】委卖完毕,默认成功")
|
# 计算并更新剩余可用持仓数量
|
data_cache.account_positions[index]['volume'] = position_volume_yesterday - sell_order_volume
|
if data_cache.account_positions[index]['volume'] <= 0:
|
logger.info(f"data_cache.account_positions == {data_cache.account_positions}")
|
logger.info(f"下单后,【{sec_name}】的剩余可用持仓数量==={data_cache.account_positions[index]['volume']}")
|
# 本票本次卖票,可用仓位为0或小于0,,移除【可用持仓代码】集合
|
'''
|
全局变量中的可用个股数量,由于只在【集合竞价】阶段用,如果移除会影响进入次数,暂不考虑使用
|
'''
|
# data_cache.available_symbols_set.remove(symbol)
|
# logger.info(f"【{sec_name}】当日可用仓位数卖完了")
|
# logger.info(f"卖后可用持仓票数:::{len(data_cache.available_symbols_set)}")
|
if symbol in data_cache.account_positions:
|
for i in data_cache.account_positions:
|
if i['symbol'] == symbol:
|
logger.info(f"下单后【{sec_name}】持仓手数volume==={i['volume']}")
|
if i['volume'] == 0:
|
# 本票本次卖票,全部持仓仓位为0,,移除【持仓代码】集合
|
data_cache.position_symbols_set.remove(symbol)
|
logger.info(f"【{sec_name}】的持仓已经卖完了,或代码已经不在持仓中")
|
logger.info(f"卖后持仓票数:::{len(data_cache.position_symbols_set)}")
|
else:
|
logger.info(
|
f"【{sec_name}】,可用持仓:{position_volume_yesterday}小于计划委托:{sell_order_volume},无法委托,直接平仓!")
|
sell_order_by_volume(symbol, position_volume_yesterday, sec_name, today_limit_down_price)
|
# 计算并更新剩余可用持仓数量
|
data_cache.account_positions[index]['volume'] = position_volume_yesterday - position_volume_yesterday
|
else:
|
logger.info(f"委托量小于等于零,委托失败!")
|
logger.info(
|
f"【{sec_name}】,可用持仓:{position_volume_yesterday},计划委托:{sell_order_volume}<=0 ?,无法委托,直接委卖100!")
|
sell_order_by_volume(symbol, 100, sec_name, today_limit_down_price)
|
# 计算并更新剩余可用持仓数量
|
data_cache.account_positions[index]['volume'] = position_volume_yesterday - 100
|
|
|
def run():
|
class MyTradeCallback(huaxin_trade_api.TradeCallback):
|
def on_order(self, order_info):
|
"""
|
订单状态改变回调
|
:param order_info: {'sinfo': 'b_603682_1736312765623', 'securityID': '603682', 'orderLocalID': '8100043081', 'direction': '0', 'orderSysID': '110018100043081', 'insertTime': '13:06:04', 'insertDate': '20250108', 'acceptTime': '13:05:46', 'cancelTime': '', 'limitPrice': 6.45, 'accountID': '00032047', 'orderRef': 130608, 'turnover': 6410.0, 'volume': 1000, 'volumeTraded': 1000, 'orderStatus': '4', 'orderSubmitStatus': '1', 'statusMsg': ''}
|
:return:
|
"""
|
print(f"收到订单回调:{order_info}")
|
logger_debug.info(f"收到订单回调:{order_info}")
|
if huaxin_util.is_deal(order_info['orderStatus']):
|
# 成交,需要更新持仓/委托/成交
|
huaxin_trade_data_update.add_position_list()
|
huaxin_trade_data_update.add_delegate_list("成交")
|
huaxin_trade_data_update.add_deal_list()
|
else:
|
huaxin_trade_data_update.add_money_list()
|
huaxin_trade_data_update.add_delegate_list("订单状态变化")
|
# 推送订单数据
|
threading.Thread(target=lambda: middle_api_protocol.push(
|
middle_api_protocol.load_push_msg({"type": "order", "data": order_info})), daemon=True).start()
|
|
queue = multiprocessing.Queue()
|
huaxin_trade_api.run_trade(queue, MyTradeCallback())
|
threading.Thread(target=data_server.run, daemon=True).start()
|