添加在休市期间模拟买入卖出

This commit is contained in:
zhiyong 2025-04-29 16:59:22 +08:00
parent c185fccd24
commit 24be80288a
4 changed files with 184 additions and 3 deletions

View File

@ -6,6 +6,9 @@ class Config:
HOST = os.getenv('TRADE_SERVER_HOST', '0.0.0.0')
DEBUG = False
# Trading settings
TRADE_TIMEOUT = int(os.getenv('TRADE_TIMEOUT', 3)) # 交易超时时间(秒)
# Trading hours
MARKET_OPEN_TIME = "09:20"
MARKET_ACTIVE_TIME = "09:15"

51
src/example_trade.py Normal file
View File

@ -0,0 +1,51 @@
import requests
# 服务器地址
URL = "http://localhost:9527/yu"
def buy(code: str, price: float, amount: int) -> dict:
"""买入股票
Args:
code: 股票代码例如 "601988.SH"
price: 买入价格
amount: 买入数量
Returns:
dict: 交易结果
"""
data = {
"code": code,
"price": str(price),
"amount": str(amount)
}
response = requests.post(f"{URL}/buy", json=data)
return response.json()
def sell(code: str, price: float, amount: int) -> dict:
"""卖出股票
Args:
code: 股票代码例如 "601988.SH"
price: 卖出价格
amount: 卖出数量
Returns:
dict: 交易结果
"""
data = {
"code": code,
"price": str(price),
"amount": str(amount)
}
response = requests.post(f"{URL}/sell", json=data)
return response.json()
if __name__ == "__main__":
# 示例买入中国银行1000股价格3.45
result = buy("601988.SH", 3.45, 1000)
print("买入结果:", result)
# 示例卖出中国银行1000股价格3.48
result = sell("601988.SH", 3.48, 1000)
print("卖出结果:", result)

View File

@ -9,8 +9,39 @@ from config import Config
import logging
import os
from logging.handlers import RotatingFileHandler
import concurrent.futures
from concurrent.futures import TimeoutError
# 配置模拟交易日志
def setup_simulation_logger():
sim_logger = logging.getLogger('trade_simulation')
sim_logger.setLevel(logging.INFO)
# 确保没有重复的处理器
for handler in sim_logger.handlers[:]:
sim_logger.removeHandler(handler)
# 文件处理器
log_dir = Config.LOG_DIR
if not os.path.exists(log_dir):
os.makedirs(log_dir)
file_handler = RotatingFileHandler(
os.path.join(log_dir, 'trade_simulation.log'),
maxBytes=Config.LOG_MAX_BYTES,
backupCount=Config.LOG_BACKUP_COUNT
)
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s'))
sim_logger.addHandler(file_handler)
# 控制台处理器
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s'))
sim_logger.addHandler(console_handler)
return sim_logger
# 配置日志
def setup_logger():
log_dir = Config.LOG_DIR
@ -48,6 +79,7 @@ def setup_logger():
return logger
logger = setup_logger()
sim_logger = setup_simulation_logger()
def run_daily(time_str, job_func):
@ -107,8 +139,33 @@ def buy():
if price <= 0 or amount <= 0:
raise ValueError("Price and amount must be positive")
# 检查交易状态
should_simulate = True
simulation_reason = "未知原因"
if trader is None:
simulation_reason = "交易实例未初始化"
else:
try:
if not trader.is_trading_time():
simulation_reason = "当前为非交易时段"
else:
should_simulate = False
except Exception as e:
simulation_reason = f"检查交易时间发生错误: {str(e)}"
if should_simulate:
# 记录模拟交易信息
sim_message = f"模拟买入 - {simulation_reason} - 代码: {code}, 价格: {price}, 数量: {amount}"
sim_logger.info(sim_message)
return jsonify({"success": True, "data": {"order_id": "simulation", "message": sim_message}}), 200
# 实际交易
logger.info(f"Executing buy order: code={code}, price={price}, amount={amount}")
result = trader.buy(code, price, amount)
result = execute_with_timeout(trader.buy, Config.TRADE_TIMEOUT, code, price, amount)
if result is None:
logger.error(f"Buy order timeout after {Config.TRADE_TIMEOUT} seconds")
return jsonify({"success": False, "error": "Operation timeout"}), 408
logger.info(f"Buy order result: {result}")
response = {"success": True, "data": result}
@ -141,8 +198,33 @@ def sell():
if price <= 0 or amount <= 0:
raise ValueError("Price and amount must be positive")
# 检查交易状态
should_simulate = True
simulation_reason = "未知原因"
if trader is None:
simulation_reason = "交易实例未初始化"
else:
try:
if not trader.is_trading_time():
simulation_reason = "当前为非交易时段"
else:
should_simulate = False
except Exception as e:
simulation_reason = f"检查交易时间发生错误: {str(e)}"
if should_simulate:
# 记录模拟交易信息
sim_message = f"模拟卖出 - {simulation_reason} - 代码: {code}, 价格: {price}, 数量: {amount}"
sim_logger.info(sim_message)
return jsonify({"success": True, "data": {"order_id": "simulation", "message": sim_message}}), 200
# 实际交易
logger.info(f"Executing sell order: code={code}, price={price}, amount={amount}")
result = trader.sell(code, price, amount)
result = execute_with_timeout(trader.sell, Config.TRADE_TIMEOUT, code, price, amount)
if result is None:
logger.error(f"Sell order timeout after {Config.TRADE_TIMEOUT} seconds")
return jsonify({"success": False, "error": "Operation timeout"}), 408
logger.info(f"Sell order result: {result}")
response = {"success": True, "data": result}
@ -230,6 +312,16 @@ def get_today_entrust():
abort(500, description="Internal server error")
# 超时处理函数
def execute_with_timeout(func, timeout, *args, **kwargs):
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
future = executor.submit(func, *args, **kwargs)
try:
return future.result(timeout=timeout)
except TimeoutError:
return None
if __name__ == "__main__":
logger.info(f"Server starting on {Config.HOST}:{Config.PORT}")
app.run(debug=Config.DEBUG, host=Config.HOST, port=Config.PORT)

View File

@ -6,7 +6,8 @@ from config import Config
from xtquant.xttrader import XtQuantTrader
from xtquant.xttype import StockAccount
from xtquant import xtconstant
from xtquant.xtdata import get_instrument_detail
from xtquant.xtdata import get_instrument_detail, get_trading_time
import datetime as dt
# 日志配置
LOG_DIR = "log"
@ -186,6 +187,40 @@ class XtTrader:
result = self.xt_trader.cancel_order_stock(self.account, int(entrust_no))
return {"cancel_result": result}
def is_trading_time(self):
"""判断当前是否为交易时间,使用中国银行(601988.SH)作为判断标的
Returns:
bool: True 表示当前为交易时间False 表示当前休市
"""
try:
# 使用中国银行股票作为判断标的
code = "601988.SH"
# 获取交易时段
trading_periods = get_trading_time(code)
if not trading_periods:
logger.error("获取交易时段失败")
return False
# 获取当前时间
now = dt.datetime.now().time()
current_seconds = now.hour * 3600 + now.minute * 60 + now.second
# 检查是否在任一交易时段内
for period in trading_periods:
start_time = period[0] # 开始时间(秒)
end_time = period[1] # 结束时间(秒)
period_type = period[2] # 交易类型2-开盘竞价3-连续交易8-收盘竞价9-盘后定价)
if start_time <= current_seconds <= end_time and period_type in [2, 3, 8]:
return True
return False
except Exception as e:
logger.error(f"判断交易时间发生错误: {str(e)}")
return False
if __name__ == "__main__":
trader = XtTrader()
trader.login()