Files
Quant_Code/temp/dingdanliu_nb_option.py
zhoujie 800883b6ec Add data retrieval and processing scripts for futures data
- Implemented a function to fetch futures data from the API with error handling and response validation.
- Added example usage for fetching and saving K-line data to CSV.
- Updated CSV files with new data entries for specified date ranges.
- Enhanced the structure of the data retrieval function to include parameters for depth and adjust type.
2025-11-21 20:24:49 +08:00

1736 lines
77 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
该代码的主要目的是处理Tick数据并生成交易信号。代码中定义了一个tickcome函数它接收到Tick数据后会进行一系列的处理包括构建Tick字典、更新上一个Tick的成交量、保存Tick数据、生成K线数据等。其中涉及到的一些函数有
on_tick(tick): 处理单个Tick数据根据Tick数据生成K线数据。
tickdata(df, symbol): 处理Tick数据生成K线数据。
orderflow_df_new(df_tick, df_min, symbol): 处理Tick和K线数据生成订单流数据。F
GetOrderFlow_dj(kData): 计算订单流的信号指标。
除此之外代码中还定义了一个MyTrader类继承自TraderApiBase用于实现交易相关的功能。
"""
# from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Process, Queue
import queue
import threading
# from AlgoPlus.CTP.MdApi import run_tick_engine
# from AlgoPlus.CTP.FutureAccount import get_simulate_account
# from AlgoPlus.CTP.FutureAccount import FutureAccount
# from AlgoPlus.CTP.TraderApiBase import TraderApiBase
from CtpPlus.CTP.MdApi import run_tick_engine
from CtpPlus.CTP.FutureAccount import get_simulate_account
from CtpPlus.CTP.FutureAccount import FutureAccount
from CtpPlus.CTP.TraderApiBase import TraderApiBase
# from AlgoPlus.ta.time_bar import tick_to_bar
import pandas as pd
from datetime import datetime, timedelta
from datetime import time as s_time
import operator
import time
import numpy as np
import os
import re
# import talib as tb
import akshare as ak
import ast
# 加入邮件通知
import smtplib
from email.mime.text import MIMEText # 导入 MIMEText 类发送纯文本邮件
from email.mime.multipart import (
MIMEMultipart,
)
# from email.mime.application import MIMEApplication
# 配置邮件信息
receivers = ["240884432@qq.com"] # 设置邮件接收人地址
subject = "TD_Simnow_Signal" # 设置邮件主题 订单流策略交易信号
# 配置邮件服务器信息
smtp_server = "smtp.qq.com" # 设置发送邮件的 SMTP 服务器地址
smtp_port = 465 # 设置发送邮件的 SMTP 服务器端口号,一般为 25 端口 465
sender = "240884432@qq.com" # 设置发送邮件的邮箱地址
username = "240884432@qq.com" # 设置发送邮件的邮箱用户名
password = "osjyjmbqrzxtbjbf" # zrmpcgttataabhjh设置发送邮件的邮箱密码或授权码
tickdatadict = {} # 存储Tick数据的字典
quotedict = {} # 存储行情数据的字典
ofdatadict = {} # 存储K线数据的字典
trade_dfs = {} # pd.DataFrame({}) # 存储交易数据的DataFrame对象
previous_volume = {} # 上一个Tick的成交量
tsymbollist = {}
time_period = 30
delta_rate = 0.8
dj_rate = 0.8
clearing_time_dict = {
"sc": s_time(2, 30),
"bc": s_time(1, 0),
"lu": s_time(23, 0),
"nr": s_time(23, 0),
"au": s_time(2, 30),
"ag": s_time(2, 30),
"ss": s_time(1, 0),
"sn": s_time(1, 0),
"ni": s_time(1, 0),
"pb": s_time(1, 0),
"zn": s_time(1, 0),
"al": s_time(1, 0),
"cu": s_time(1, 0),
"ru": s_time(23, 0),
"rb": s_time(23, 0),
"hc": s_time(23, 0),
"fu": s_time(23, 0),
"bu": s_time(23, 0),
"sp": s_time(23, 0),
"PF": s_time(23, 0),
"SR": s_time(23, 0),
"CF": s_time(23, 0),
"CY": s_time(23, 0),
"RM": s_time(23, 0),
"MA": s_time(23, 0),
"TA": s_time(23, 0),
"ZC": s_time(23, 0),
"FG": s_time(23, 0),
"OI": s_time(23, 0),
"SA": s_time(23, 0),
"p": s_time(23, 0),
"j": s_time(23, 0),
"jm": s_time(23, 0),
"i": s_time(23, 0),
"l": s_time(23, 0),
"v": s_time(23, 0),
"pp": s_time(23, 0),
"eg": s_time(23, 0),
"c": s_time(23, 0),
"cs": s_time(23, 0),
"y": s_time(23, 0),
"m": s_time(23, 0),
"a": s_time(23, 0),
"b": s_time(23, 0),
"rr": s_time(23, 0),
"eb": s_time(23, 0),
"pg": s_time(23, 0),
}
fees_df = pd.read_csv('./futures_fees_info.csv', header = 0, usecols= [1, 3, 5, 13, 15],names=['合约代码', '品种代码', '合约乘数', '做多保证金率(按金额)', '做空保证金率(按金额)'])
contacts_df = pd.read_csv('./main_contacts.csv', header = 0, usecols= [16, 17],names=['主连代码', '品种代码'])
def get_main_contact_on_time(main_symbol_code,contacts_df):
main_symbol = contacts_df[contacts_df['品种代码'] == main_symbol_code]['主连代码'].iloc[0]
# print("最终使用的主连代码:",main_symbol)
return main_symbol#.encode('ascii')
def send_mail(text):
msg = MIMEMultipart()
msg["From"] = sender
msg["To"] = ";".join(receivers)
msg["Subject"] = subject
msg.attach(MIMEText(text, "plain", "utf-8"))
smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
smtp.login(username, password)
smtp.sendmail(sender, receivers, msg.as_string())
smtp.quit()
# def get_otm_put_strike_price(option_finance_board_df, future_price):
# # 计算距离当前期货价格最近的行权价
# option_finance_board_df['strike_diff'] = abs(option_finance_board_df['行权价'] - future_price)
# closest_row = option_finance_board_df.loc[option_finance_board_df['strike_diff'].idxmin()]
# otm_put_strike_price = closest_row['行权价']
# return otm_put_strike_price
def send_feishu_message(text):
headers = {
"Content-Type": "application/json"
}
data = {
"msg_type": "text",
"content": {
"text": text
}
}
# response = requests.post("https://open.feishu.cn/open-apis/bot/v2/hook/8608dfa4-e599-462a-8dba-6ac72873dd27", headers=headers, json=data) #AI策略飞书地址
response = requests.post("https://open.feishu.cn/open-apis/bot/v2/hook/fae322eb-1ff7-4133-ba00-0ca4895d205e", headers=headers, json=data) #订单流策略飞书地址
if response.status_code != 200:
print(f"飞书消息发送失败,状态码: {response.status_code}, 响应内容: {response.text}")
# def futures_main_day(future_symbol, delta_days):
# # 获取当前日期的数据
# today = datetime.now().strftime("%Y%m%d")
# # 计算多少日前的日期
# start_day = (datetime.now() - timedelta(days=delta_days)).strftime("%Y%m%d")
# futures_main_sina_hist = ak.futures_main_sina(
# symbol=future_symbol, start_date=start_day, end_date=today
# )
# return futures_main_sina_hist
# 交易程序---------------------------------------------------------------------------------------------------------------------------------------------------------------------
class ParamObj:
symbol = None # 合约名称
Lots = None # 下单手数
py = None # 设置委托价格的偏移,更加容易促成成交
trailing_stop_percent = None # 跟踪出场参数
fixed_stop_loss_percent = None # 固定出场参数
dj_X = None # 开仓的堆积参数
delta = None # 开仓的delta参数
sum_delta = None # 开仓的delta累积参数
失衡 = None
堆积 = None
周期 = None
# 策略需要用到的变量
cont_df = 0
pos = 0
short_trailing_stop_price = 0
long_trailing_stop_price = 0
sl_long_price = 0
sl_shor_price = 0
out_long = 0
out_short = 0
clearing_executed = False
kgdata = True
def __init__(
self,
symbol,
Lots,
py,
trailing_stop_percent,
fixed_stop_loss_percent,
dj_X,
delta,
sum_delta,
失衡,
堆积,
周期,
):
self.symbol = symbol
self.Lots = Lots
self.py = py
self.trailing_stop_percent = trailing_stop_percent
self.fixed_stop_loss_percent = fixed_stop_loss_percent
self.dj_X = dj_X
self.delta = delta
self.sum_delta = sum_delta
self.失衡 = 失衡
self.堆积 = 堆积
self.周期 = 周期
class MyTrader(TraderApiBase):
def __init__(
self,
broker_id,
td_server,
investor_id,
password,
app_id,
auth_code,
md_queue=None,
page_dir="",
private_resume_type=2,
public_resume_type=2,
):
self.param_dict = {}
self.queue_dict = {}
self.品种 = " "
def tickcome(self, md_queue):
global previous_volume
data = md_queue
instrument_id = data["InstrumentID"].decode() # 品种代码
ActionDay = data["ActionDay"].decode() # 交易日日期
update_time = data["UpdateTime"].decode() # 更新时间
update_millisec = str(data["UpdateMillisec"]) # 更新毫秒数
created_at = (
ActionDay[:4]
+ "-"
+ ActionDay[4:6]
+ "-"
+ ActionDay[6:]
+ " "
+ update_time
+ "."
+ update_millisec
) # 创建时间
# 构建tick字典
tick = {
"symbol": instrument_id, # 品种代码和交易所ID
"created_at": datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S.%f"),
# "created_at": datetime.strptime(created_at, "-- %H:%M:%S.%f"),
"price": float(data["LastPrice"]), # 最新价
"last_volume": (
int(data["Volume"]) - previous_volume.get(instrument_id, 0)
if previous_volume.get(instrument_id, 0) != 0
else 0
), # 瞬时成交量
"bid_p": float(data["BidPrice1"]), # 买价
"bid_v": int(data["BidVolume1"]), # 买量
"ask_p": float(data["AskPrice1"]), # 卖价
"ask_v": int(data["AskVolume1"]), # 卖量
"UpperLimitPrice": float(data["UpperLimitPrice"]), # 涨停价
"LowerLimitPrice": float(data["LowerLimitPrice"]), # 跌停价
"TradingDay": data["TradingDay"].decode(), # 交易日日期
"cum_volume": int(data["Volume"]), # 最新总成交量
"cum_amount": float(data["Turnover"]), # 最新总成交额
"cum_position": int(data["OpenInterest"]), # 合约持仓量
}
previous_volume[instrument_id] = int(data["Volume"])
if tick["last_volume"] > 0:
self.on_tick(tick)
def can_time(self, hour, minute):
hour = str(hour)
minute = str(minute)
if len(minute) == 1:
minute = "0" + minute
return int(hour + minute)
def on_tick(self, tick):
# tm = self.can_time(tick["created_at"].hour, tick["created_at"].minute)
if tick["last_volume"] == 0:
return
quotes = tick
timetick = str(tick["created_at"]).replace("+08:00", "")
tsymbol = tick["symbol"]
if tsymbol not in tsymbollist.keys():
# 获取tick的买卖价和买卖量
tsymbollist[tsymbol] = tick
bid_p = quotes["bid_p"]
ask_p = quotes["ask_p"]
bid_v = quotes["bid_v"]
ask_v = quotes["ask_v"]
else:
# 获取上一个tick的买卖价和买卖量
rquotes = tsymbollist[tsymbol]
bid_p = rquotes["bid_p"]
ask_p = rquotes["ask_p"]
bid_v = rquotes["bid_v"]
ask_v = rquotes["ask_v"]
tsymbollist[tsymbol] = tick
tick_dt = pd.DataFrame(
{
"datetime": timetick,
"symbol": tick["symbol"],
"mainsym": tick["symbol"].rstrip("0123456789").upper(),
"lastprice": tick["price"],
"vol": tick["last_volume"],
"bid_p": bid_p,
"ask_p": ask_p,
"bid_v": bid_v,
"ask_v": ask_v,
},
index=[0],
)
sym = tick_dt["symbol"][0]
self.tickdata(tick_dt, sym)
def data_of(self, symbol, df):
global trade_dfs
trade_dfs[symbol] = pd.concat([trade_dfs[symbol], df], ignore_index=True)
def process(self, bidDict, askDict, symbol):
try:
# 尝试从quotedict中获取对应品种的报价数据
dic = quotedict[symbol]
bidDictResult = dic["bidDictResult"]
askDictResult = dic["askDictResult"]
except Exception:
# 如果获取失败则初始化bidDictResult和askDictResult为空字典
bidDictResult, askDictResult = {}, {}
# 将所有买盘字典和卖盘字典的key合并并按升序排序
sList = sorted(set(list(bidDict.keys()) + list(askDict.keys())))
# 遍历所有的key将相同key的值进行累加
for s in sList:
if s in bidDict:
if s in bidDictResult:
bidDictResult[s] = int(bidDict[s]) + bidDictResult[s]
else:
bidDictResult[s] = int(bidDict[s])
if s not in askDictResult:
askDictResult[s] = 0
else:
if s in askDictResult:
askDictResult[s] = int(askDict[s]) + askDictResult[s]
else:
askDictResult[s] = int(askDict[s])
if s not in bidDictResult:
bidDictResult[s] = 0
# 构建包含bidDictResult和askDictResult的字典并存入quotedict中
df = {"bidDictResult": bidDictResult, "askDictResult": askDictResult}
quotedict[symbol] = df
return bidDictResult, askDictResult
def tickdata(self, df, symbol):
tickdata = pd.DataFrame(
{
"datetime": df["datetime"],
"symbol": df["symbol"],
"lastprice": df["lastprice"],
"volume": df["vol"],
"bid_p": df["bid_p"],
"bid_v": df["bid_v"],
"ask_p": df["ask_p"],
"ask_v": df["ask_v"],
}
)
try:
if symbol in tickdatadict.keys():
rdf = tickdatadict[symbol]
rdftm = pd.to_datetime(rdf["bartime"][0]).strftime("%Y-%m-%d %H:%M:%S")
now = str(tickdata["datetime"][0])
if now > rdftm:
try:
oo = ofdatadict[symbol]
self.data_of(symbol, oo)
if symbol in quotedict.keys():
quotedict.pop(symbol)
if symbol in tickdatadict.keys():
tickdatadict.pop(symbol)
if symbol in ofdatadict.keys():
ofdatadict.pop(symbol)
except IOError as e:
print("rdftm捕获到异常", e)
tickdata["bartime"] = pd.to_datetime(tickdata["datetime"])
tickdata["open"] = tickdata["lastprice"]
tickdata["high"] = tickdata["lastprice"]
tickdata["low"] = tickdata["lastprice"]
tickdata["close"] = tickdata["lastprice"]
tickdata["starttime"] = tickdata["datetime"]
else:
tickdata["bartime"] = rdf["bartime"]
tickdata["open"] = rdf["open"]
tickdata["high"] = max(
tickdata["lastprice"].values, rdf["high"].values
)
tickdata["low"] = min(
tickdata["lastprice"].values, rdf["low"].values
)
tickdata["close"] = tickdata["lastprice"]
tickdata["volume"] = df["vol"] + rdf["volume"].values
tickdata["starttime"] = rdf["starttime"]
else:
print("新bar的第一个tick进入")
tickdata["bartime"] = pd.to_datetime(tickdata["datetime"])
tickdata["open"] = tickdata["lastprice"]
tickdata["high"] = tickdata["lastprice"]
tickdata["low"] = tickdata["lastprice"]
tickdata["close"] = tickdata["lastprice"]
tickdata["starttime"] = tickdata["datetime"]
except IOError as e:
print("捕获到异常", e)
tickdata["bartime"] = pd.to_datetime(tickdata["bartime"])
param = self.param_dict[self.品种]
bardata = (
tickdata.resample(
on="bartime", rule=param.周期, label="right", closed="right"
)
.agg(
{
"starttime": "first",
"symbol": "last",
"open": "first",
"high": "max",
"low": "min",
"close": "last",
"volume": "sum",
}
)
.reset_index(drop=False)
)
bardata = bardata.dropna().reset_index(drop=True)
bardata["bartime"] = pd.to_datetime(bardata["bartime"][0]).strftime(
"%Y-%m-%d %H:%M:%S"
)
tickdatadict[symbol] = bardata
tickdata["volume"] = df["vol"].values
self.orderflow_df_new(tickdata, bardata, symbol)
def orderflow_df_new(self, df_tick, df_min, symbol):
# startArray = pd.to_datetime(df_min["starttime"]).values
voluememin = df_min["volume"].values
highs = df_min["high"].values
lows = df_min["low"].values
opens = df_min["open"].values
closes = df_min["close"].values
# endArray = pd.to_datetime(df_min['bartime']).values
endArray = df_min["bartime"].values
# print(endArray)
# deltaArray = np.zeros((len(endArray),))
# tTickArray = pd.to_datetime(df_tick["datetime"]).values
bp1minickArray = df_tick["bid_p"].values
ap1minickArray = df_tick["ask_p"].values
lastTickArray = df_tick["lastprice"].values
volumeTickArray = df_tick["volume"].values
symbolarray = df_tick["symbol"].values
# indexFinal = 0
for index, tEnd in enumerate(endArray):
dt = endArray[index]
# start = startArray[index]
bidDict = {}
askDict = {}
bar_vol = voluememin[index]
bar_close = closes[index]
bar_open = opens[index]
bar_low = lows[index]
bar_high = highs[index]
bar_symbol = symbolarray[index]
Bp = round(bp1minickArray[0], 4)
Ap = round(ap1minickArray[0], 4)
LastPrice = round(lastTickArray[0], 4)
Volume = volumeTickArray[0]
if LastPrice >= Ap:
if str(LastPrice) in askDict.keys():
askDict[str(LastPrice)] += Volume
else:
askDict[str(LastPrice)] = Volume
if LastPrice <= Bp:
if str(LastPrice) in bidDict.keys():
bidDict[str(LastPrice)] += Volume
else:
bidDict[str(LastPrice)] = Volume
# indexFinal = indexTick
bidDictResult, askDictResult = self.process(bidDict, askDict, symbol)
bidDictResult = dict(
sorted(bidDictResult.items(), key=operator.itemgetter(0))
)
askDictResult = dict(
sorted(askDictResult.items(), key=operator.itemgetter(0))
)
prinslist = list(bidDictResult.keys())
asklist = list(askDictResult.values())
bidlist = list(bidDictResult.values())
delta = sum(askDictResult.values()) - sum(bidDictResult.values())
df = pd.DataFrame(
{
"price": pd.Series([prinslist]),
"Ask": pd.Series([asklist]),
"Bid": pd.Series([bidlist]),
}
)
# df=pd.DataFrame({'price':pd.Series(bidDictResult.keys()),'Ask':pd.Series(askDictResult.values()),'Bid':pd.Series(bidDictResult.values())})
df["symbol"] = bar_symbol
df["datetime"] = dt
df["delta"] = str(delta)
df["close"] = bar_close
df["open"] = bar_open
df["high"] = bar_high
df["low"] = bar_low
df["volume"] = bar_vol
# df['ticktime']=tTickArray[0]
df["dj"] = self.GetOrderFlow_dj(df)
ofdatadict[symbol] = df
def GetOrderFlow_dj(self, kData):
param = self.param_dict[self.品种]
Config = {
"Value1": param.失衡,
"Value2": param.堆积,
"Value4": True,
}
aryData = kData
djcout = 0
# 遍历kData中的每一行计算djcout指标
for index, row in aryData.iterrows():
kItem = aryData.iloc[index]
# high = kItem["high"]
# low = kItem["low"]
# close = kItem["close"]
# open = kItem["open"]
dtime = kItem["datetime"]
price_s = kItem["price"]
Ask_s = kItem["Ask"]
Bid_s = kItem["Bid"]
delta = kItem["delta"]
price_s = price_s
Ask_s = Ask_s
Bid_s = Bid_s
gj = 0
xq = 0
gxx = 0
xxx = 0
# 遍历price_s中的每一个元素计算相关指标
for i in np.arange(0, len(price_s), 1):
duiji = {
"price": 0,
"time": 0,
"longshort": 0,
}
if i == 0:
delta = delta
order = {
"Price": price_s[i],
"Bid": {"Value": Bid_s[i]},
"Ask": {"Value": Ask_s[i]},
}
# 空头堆积
if i >= 0 and i < len(price_s) - 1:
if order["Bid"]["Value"] > Ask_s[i + 1] * int(Config["Value1"]):
gxx += 1
gj += 1
if gj >= int(Config["Value2"]) and Config["Value4"] is True:
duiji["price"] = price_s[i]
duiji["time"] = dtime
duiji["longshort"] = -1
if float(duiji["price"]) > 0:
djcout += -1
else:
gj = 0
# 多头堆积
if i >= 1 and i < len(price_s) - 1:
if order["Ask"]["Value"] > Bid_s[i - 1] * int(Config["Value1"]):
xq += 1
xxx += 1
if xq >= int(Config["Value2"]) and Config["Value4"] is True:
duiji["price"] = price_s[i]
duiji["time"] = dtime
duiji["longshort"] = 1
if float(duiji["price"]) > 0:
djcout += 1
else:
xq = 0
# 返回计算得到的djcout值
return djcout
# 读取保存的数据
def read_to_csv(self, symbol):
# 文件夹路径和文件路径
# 使用正则表达式提取英文字母并重新赋值给symbol
param = self.param_dict[symbol]
# symbol = ''.join(re.findall('[a-zA-Z]', str(symbol)))
folder_path = "traderdata"
file_path = os.path.join(folder_path, f"{str(symbol)}_traderdata.csv")
# 如果文件夹不存在则创建
if not os.path.exists(folder_path):
os.makedirs(folder_path)
# 读取保留的模型数据CSV文件
if os.path.exists(file_path):
df = pd.read_csv(file_path)
if not df.empty and param.kgdata is True:
# 选择最后一行数据
# df = df._append(df.iloc[-1], ignore_index=True)
row = df.iloc[-1]
# 根据CSV文件的列名将数据赋值给相应的属性
param.pos = int(row["pos"])
param.short_trailing_stop_price = float(
row["short_trailing_stop_price"]
)
param.long_trailing_stop_price = float(row["long_trailing_stop_price"])
param.sl_long_price = float(row["sl_long_price"])
param.sl_shor_price = float(row["sl_shor_price"])
# param.out_long = int(row['out_long'])
# param.out_short = int(row['out_short'])
print("找到历史交易数据文件,已经更新持仓,止损止盈数据", df.iloc[-1])
param.kgdata = False
else:
pass
# print("没有找到历史交易数据文件", file_path)
# 如果没有找到CSV则初始化变量
pass
# 保存数据
def save_to_csv(self, symbol):
param = self.param_dict[symbol]
# 使用正则表达式提取英文字母并重新赋值给symbol
# symbol = ''.join(re.findall('[a-zA-Z]', str(symbol)))
# 创建DataFrame
data = {
"datetime": [trade_dfs[symbol]["datetime"].iloc[-1]],
"pos": [param.pos],
"short_trailing_stop_price": [param.short_trailing_stop_price],
"long_trailing_stop_price": [param.long_trailing_stop_price],
"sl_long_price": [param.sl_long_price],
"sl_shor_price": [param.sl_shor_price],
# 'out_long': [param.out_long],
# 'out_short': [param.out_short]
}
df = pd.DataFrame(data)
# 将DataFrame保存到CSV文件
# df.to_csv(
# f"traderdata/{str(symbol)}_traderdata.csv",
# mode="a",
# index=False,
# header=False,
# )
traderdata_file_path = f"traderdata/{str(symbol)}_traderdata.csv"
if os.path.exists(traderdata_file_path):
# 仅保存最后一行数据
# csv_df = pd.read_csv(traderdata_file_path)
# if df["pos"].iloc[-1] != csv_df["pos"].iloc[-1]:
df.to_csv(traderdata_file_path, mode="a", header=False, index=False)
else:
# 创建新文件并保存整个DataFrame
df.to_csv(traderdata_file_path, index=False)
# df.to_csv(f"traderdata/{str(symbol)}_traderdata.csv", index=False)
# 每日收盘重置数据
def day_data_reset(self, symbol):
param = self.param_dict[symbol]
sec = "".join(re.findall("[a-zA-Z]", str(symbol)))
# 获取当前时间
current_time = datetime.now().time()
# 第一时间范围(日盘收盘)
clearing_time1_start = s_time(15, 5)
clearing_time1_end = s_time(15, 10)
# 创建一个标志变量,用于记录是否已经执行过
param.clearing_executed = False
# 检查当前时间第一个操作的时间范围内
if (
clearing_time1_start <= current_time <= clearing_time1_end
and not param.clearing_executed
):
param.clearing_executed = True # 设置标志变量为已执行
trade_dfs[symbol].drop(
trade_dfs[symbol].index, inplace=True
) # 清除当天的行情数据
# 检查当前时间是否在第二个操作的时间范围内(夜盘收盘)
elif sec in clearing_time_dict.keys():
clearing_time2_start = clearing_time_dict[sec]
clearing_time2_end = s_time(
clearing_time2_start.hour, clearing_time2_start.minute + 15
)
if (
clearing_time2_start <= current_time <= clearing_time2_end
and not param.clearing_executed
):
param.clearing_executed = True # 设置标志变量为已执行
trade_dfs[symbol].drop(
trade_dfs[symbol].index, inplace=True
) # 清除当天的行情数据
else:
param.clearing_executed = False
pass
return param.clearing_executed
def OnRtnTrade(self, pTrade):
print("||成交回报||", pTrade)
def OnRspOrderInsert(self, pInputOrder, pRspInfo, nRequestID, bIsLast):
print("||OnRspOrderInsert||", pInputOrder, pRspInfo, nRequestID, bIsLast)
# 订单状态通知
def OnRtnOrder(self, pOrder):
print("||订单回报||", pOrder)
def cal_sig(self, symbol_queue):
while True:
try:
data = symbol_queue.get(
block=True, timeout=5
) # 如果5秒没收到新的tick行情则抛出异常
instrument_id = data["InstrumentID"].decode() # 品种代码
size = symbol_queue.qsize()
if size > 1:
print(
f"当前{instrument_id}共享队列长度为{size}, 有点阻塞!!!!!"
)
self.read_to_csv(instrument_id)
self.day_data_reset(instrument_id)
param = self.param_dict[instrument_id]
self.品种 = instrument_id
self.tickcome(data)
trade_df = trade_dfs[instrument_id]
# 新K线开始启动交易程序 and 保存行情数据
self.read_to_csv(instrument_id)
if len(trade_df) > param.cont_df:
# 检查文件是否存在
csv_file_path = f"traderdata/{instrument_id}_ofdata.csv"
# if os.path.exists(csv_file_path):
# #jerome :保存数增加'delta累计'、POC、、终极平滑值、趋势方向
# # 仅保存最后一行数据
# trade_df.tail(1).to_csv(
# csv_file_path, mode="a", header=False, index=False
# )
# else:
# # 创建新文件并保存整个DataFrame
# trade_df.to_csv(csv_file_path, index=False)
# 检查是否存在重复行
if os.path.exists(csv_file_path):
existing_df = pd.read_csv(csv_file_path, usecols=range(12))
# 获取要写入的新数据
new_data = trade_df.tail(1)
# 检查新数据是否与现有数据重复
is_duplicate = False
for _, row in existing_df.iterrows():
if (row['datetime'] == new_data['datetime'].iloc[0] and
row['price'] == new_data['price'].iloc[0] and
row['Ask'] == new_data['Ask'].iloc[0] and
row['Bid'] == new_data['Bid'].iloc[0] and
row['symbol'] == new_data['symbol'].iloc[0] and
row['delta'] == new_data['delta'].iloc[0] and
row['close'] == new_data['close'].iloc[0] and
row['open'] == new_data['open'].iloc[0] and
row['high'] == new_data['high'].iloc[0] and
row['low'] == new_data['low'].iloc[0] and
row['volume'] == new_data['volume'].iloc[0] and
row['dj'] == new_data['dj'].iloc[0]):
is_duplicate = True
break
# 检查Ask和Bid的值是否为空或全为0
ask_value = new_data['Ask'].iloc[0]
bid_value = new_data['Bid'].iloc[0]
is_valid_data = (
ask_value != [] and
ask_value != [0] and
bid_value != [] and
bid_value != [0]
)
if not is_duplicate and is_valid_data:
# 如果没有重复且数据有效,则写入新数据
new_data.to_csv(
csv_file_path, mode="a", header=False, index=False
)
else:
# 如果文件不存在,直接写入新数据
trade_df.to_csv(csv_file_path, index=False)
# 更新跟踪止损价格
if param.long_trailing_stop_price > 0 and param.pos > 0:
param.long_trailing_stop_price = (
trade_df["low"].iloc[-1]
if param.long_trailing_stop_price < trade_df["low"].iloc[-1]
else param.long_trailing_stop_price
)
self.save_to_csv(instrument_id)
if param.short_trailing_stop_price > 0 and param.pos < 0:
param.short_trailing_stop_price = (
trade_df["high"].iloc[-1]
if trade_df["high"].iloc[-1]
< param.short_trailing_stop_price
else param.short_trailing_stop_price
)
self.save_to_csv(instrument_id)
param.out_long = param.long_trailing_stop_price * (
1 - param.trailing_stop_percent
)
param.out_short = param.short_trailing_stop_price * (
1 + param.trailing_stop_percent
)
# 跟踪出场
if param.out_long > 0:
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"预设——多头止盈——",
"TR",
param.out_long,
"low",
trade_df["low"].iloc[-1],
)
if (
trade_df["low"].iloc[-1] < param.out_long
and param.pos > 0
and param.sl_long_price > 0
and trade_df["low"].iloc[-1] > param.sl_long_price
):
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"多头止盈",
"TR",
param.out_long,
"low",
trade_df["low"].iloc[-1],
)
# 平多
self.insert_order(
data["ExchangeID"],
data["InstrumentID"],
data["BidPrice1"] - param.py,
param.Lots,
b"1",
b"1",
)
self.insert_order(
data["ExchangeID"],
data["InstrumentID"],
data["BidPrice1"] - param.py,
param.Lots,
b"1",
b"3",
)
param.long_trailing_stop_price = 0
param.out_long = 0
param.sl_long_price = 0
param.pos = 0
self.save_to_csv(instrument_id)
if param.out_short > 0:
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"预设——空头止盈——: ",
"TR",
param.out_short,
"high",
trade_df["high"].iloc[-1],
)
if (
trade_df["high"].iloc[-1] > param.out_short
and param.pos < 0
and param.sl_shor_price > 0
and trade_df["high"].iloc[-1] < param.sl_shor_price
):
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"空头止盈: ",
"TR",
param.out_short,
"high",
trade_df["high"].iloc[-1],
)
# 平空
self.insert_order(
data["ExchangeID"],
data["InstrumentID"],
data["AskPrice1"] + param.py,
param.Lots,
b"0",
b"1",
)
self.insert_order(
data["ExchangeID"],
data["InstrumentID"],
data["AskPrice1"] + param.py,
param.Lots,
b"0",
b"3",
)
param.short_trailing_stop_price = 0
param.sl_shor_price = 0
self.out_shor = 0
param.pos = 0
self.save_to_csv(instrument_id)
# 固定止损
fixed_stop_loss_L = param.sl_long_price * (
1 - param.fixed_stop_loss_percent
)
if param.pos > 0:
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"预设——多头止损",
"SL",
fixed_stop_loss_L,
"close",
trade_df["close"].iloc[-1],
)
if (
param.sl_long_price > 0
and fixed_stop_loss_L > 0
and param.pos > 0
and trade_df["close"].iloc[-1] < fixed_stop_loss_L
):
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"多头止损",
"SL",
fixed_stop_loss_L,
"close",
trade_df["close"].iloc[-1],
)
# 平多
self.insert_order(
data["ExchangeID"],
data["InstrumentID"],
data["BidPrice1"] - param.py,
param.Lots,
b"1",
b"1",
)
self.insert_order(
data["ExchangeID"],
data["InstrumentID"],
data["BidPrice1"] - param.py,
param.Lots,
b"1",
b"3",
)
param.long_trailing_stop_price = 0
param.sl_long_price = 0
param.out_long = 0
param.pos = 0
self.save_to_csv(instrument_id)
fixed_stop_loss_S = param.sl_shor_price * (
1 + param.fixed_stop_loss_percent
)
if param.pos < 0:
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"预设——空头止损",
"SL",
fixed_stop_loss_S,
"close",
trade_df["close"].iloc[-1],
)
if (
param.sl_shor_price > 0
and fixed_stop_loss_S > 0
and param.pos < 0
and trade_df["close"].iloc[-1] > fixed_stop_loss_S
):
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"空头止损",
"SL",
fixed_stop_loss_S,
"close",
trade_df["close"].iloc[-1],
)
# 平空
self.insert_order(
data["ExchangeID"],
data["InstrumentID"],
data["AskPrice1"] + param.py,
param.Lots,
b"0",
b"1",
)
self.insert_order(
data["ExchangeID"],
data["InstrumentID"],
data["AskPrice1"] + param.py,
param.Lots,
b"0",
b"3",
)
param.short_trailing_stop_price = 0
param.sl_shor_price = 0
param.out_short = 0
param.pos = 0
self.save_to_csv(instrument_id)
# 计算累积的delta值datetime.strptime(str_time, "%Y-%m-%d %H:%M:%S")
trade_df["delta"] = trade_df["delta"].astype(float)
# trade_df['datetime'] = pd.to_datetime(trade_df['datetime'], format='mixed')
trade_df['datetime'] = pd.to_datetime(trade_df['datetime'], format='%Y-%m-%d %H:%M:%S')
# 自定义分组逻辑前一日21:00至当日15:00为一天
def get_trading_day(dt):
# 如果时间在21:00之后属于下一个交易日
if dt.hour >= 21:
return (dt + pd.Timedelta(days=1)).date()
# 如果时间在15:00之前属于当前交易日
elif dt.hour < 15:
return dt.date()
# 15:00-21:00之间的数据属于当前交易日
else:
return dt.date()
trade_df['trading_day'] = trade_df['datetime'].apply(get_trading_day)
# 将日期转换为字符串
trade_df['trading_day'] = trade_df['trading_day'].astype(str)
# 按交易日计算delta累计
trade_df['delta累计'] = trade_df.groupby('trading_day')['delta'].cumsum()
trade_df = trade_df.fillna('缺值')#fillna(value=0)
def ultimate_smoother(price,period):
# 初始化变量(修正角度单位为弧度)
a1 = np.exp(-1.414 * np.pi / period)
b1 = 2 * a1 * np.cos(1.414 * np.pi / period) # 将180改为np.pi
c2 = b1
c3 = -a1 ** 2
c1 = (1 + c2 - c3) / 4
# 准备输出序列
us = np.zeros(len(price))
us_new = np.zeros(len(price))
trend = [None]*(len(price))
ma_close = np.zeros(len(price))
# 前4个点用原始价格初始化
for i in range(len(price)):
if i < 4:
us[i] = price.iloc[i]
else:
# 应用递归公式
us[i] = (1 - c1) * price.iloc[i] + (2 * c1 - c2) * price.iloc[i-1] \
- (c1 + c3) * price.iloc[i-2] + c2 * us[i-1] + c3 * us[i-2]
us_new = np.around(us, decimals=2)
ma_close = price.rolling(window=4*period).mean()#5*
# if us_new[i]>price[i] and ma_close[i]>price[i]:
# trend[i] = '空头趋势'
# elif us_new[i]<price[i] and ma_close[i]<price[i]:
# trend[i] = '多头趋势'
# else:
# trend[i] = '无趋势'
if us_new[i] < ma_close.iloc[i]:
trend[i] = '空头趋势'
elif us_new[i] > ma_close.iloc[i]:
trend[i] = '多头趋势'
else:
trend[i] = '无趋势'
return us_new,trend
trade_df['终极平滑值'],trade_df['趋势方向'] = ultimate_smoother(trade_df['close'],time_period)#,df['ma_close']
trade_df['datetime'] = trade_df['datetime'].dt.strftime("%Y-%m-%d %H:%M:%S")
def safe_literal_eval(x):
"""带异常处理的安全转换"""
try:
return ast.literal_eval(x)
except ValueError:
return [] # 返回空列表作为占位符
def add_poc_column(df):
# 安全转换列数据
df['price'] = df['price'].apply(safe_literal_eval)
df['Ask'] = df['Ask'].apply(lambda x: list(map(int, safe_literal_eval(x))))
df['Bid'] = df['Bid'].apply(lambda x: list(map(int, safe_literal_eval(x))))
# 定义处理函数(带数据验证)
def find_poc(row):
# 验证三个列表长度一致且非空
if not (len(row['price']) == len(row['Ask']) == len(row['Bid']) > 0):
return '缺值' # 返回空值标记异常数据
sums = [a + b for a, b in zip(row['Ask'], row['Bid'])]
try:
max_index = sums.index(max(sums))
return row['price'][max_index]
except ValueError:
return '缺值' # 处理空求和列表情况
# 应用处理函数
df['POC'] = df.apply(find_poc, axis=1)
# 可选:统计异常数据
error_count = df['POC'].isnull().sum()
if error_count > 0:
print(f"警告:发现 {error_count} 行异常数据已标记为NaN")
return df['POC']
trade_df['POC'] = add_poc_column(trade_df)
def finall_trend(delta_sum,trend):
f_trend = [None]*(len(delta_sum))
# delta_sum = delta_sum.astype(float)
for i in range(len(delta_sum)):
if (delta_sum[i] == '缺值') or (trend[i] == '缺值'):
f_trend[i] = '方向不明'
# return f_trend
else:
if delta_sum[i] > 0 and (trend[i] == '多头趋势'):
f_trend[i] = '强多头'
elif delta_sum[i] < 0 and (trend[i] == '空头趋势'):
f_trend[i] = '强空头'
else:
f_trend[i] = '方向不明'
return f_trend
trade_df['最终趋势'] = finall_trend(trade_df['delta累计'],trade_df['趋势方向'])
# table_text = f"品种:{trade_df['symbol'].iloc[-1]}, 时间:{trade_df['datetime'].iloc[-1]},close:{trade_df['close'].iloc[-1]},open:{trade_df['open'].iloc[-1]},high:{trade_df['high'].iloc[-1]},low:{trade_df['low'].iloc[-1]},delta:{trade_df['delta'].iloc[-1]}, delta累计:{trade_df['delta累计'].iloc[-1]}, dj:{trade_df['dj'].iloc[-1]},POC:{trade_df['POC'].iloc[-1]}, 终极平滑值:{trade_df['终极平滑值'].iloc[-1]}, 趋势方向:{trade_df['趋势方向'].iloc[-1]},最终趋势:{trade_df['最终趋势'].iloc[-1]}"
# if data["InstrumentID"]:
# option_buy_symbol,option_buy_price= get_otm_option(data["InstrumentID"], 'C')
# option_sell_symbol,option_sell_price = get_otm_option(data["InstrumentID"], 'P')
# print("买入平值期权为:", option_buy_symbol, ",价格为:", option_buy_price)
# print("卖出平值期权为:", option_sell_symbol, ",价格为:", option_sell_price)
def get_otm_option(future_symbol, trade_type):
def get_option_symbol(future_symbol):
# 创建一个字典,将期货值futuresymbol映射到对应的option symbol .
option_dict = {
"IH": "上证50股指期权",
"IF": "沪深300股指期权",
"IC": "中证500股指期权",
"IM": "中证1000股指期权"
}
# 解析 future_symbol 获取期货代码和到期月份
m = re.match(r'([A-Za-z]+)(\d+)', future_symbol)
if not m:
raise ValueError(f"future_symbol 格式不正确: {future_symbol}")
future_code, future_end_month = m.groups()
option_symbol = option_dict.get(future_code)
return option_symbol, future_end_month
try:
option_symbol, future_end_month = get_option_symbol(future_symbol)
option_finance_board_df = ak.option_finance_board(symbol=option_symbol, end_month=future_end_month)
len(option_finance_board_df)
half = len(option_finance_board_df) // 2
first_half_df = option_finance_board_df.iloc[:half]
first_half_df.columns = [f"{col}_C" for col in first_half_df.columns]
first = first_half_df.reset_index(drop=True)
second_half_df = option_finance_board_df.iloc[half:]
second_half_df.columns = [f"{col}_P" for col in second_half_df.columns]
second = second_half_df.reset_index(drop=True)
df = pd.concat([first, second], axis=1)
df['lastprice_(C-P)'] = df['lastprice_C'] - df['lastprice_P']
idx = df['lastprice_(C-P)'].abs().idxmin()
row = df.loc[idx, ['instrument_C', 'instrument_P', 'lastprice_C','lastprice_P','lastprice_(C-P)']]
# print(f"index={idx}, instrument_C={row['instrument_C']}, instrument_P={row['instrument_P']}, lastprice_(C-P)={row['lastprice_(C-P)']}")
# return df.loc[idx, ['instrument_C', 'instrument_P']]
if trade_type == 'C':
return row['instrument_C'], float(row['lastprice_C'])
elif trade_type == 'P':
return row['instrument_P'], float(row['lastprice_P'])
else:
raise ValueError(f"未知的 trade_type: {trade_type}")
except Exception as e:
print(f"get_otm_option error for {future_symbol}: {e}")
return None
def get_otm_pirce(future_symbol, trade_option_symbol):
def get_option_symbol(future_symbol):
# 创建一个字典,将期货值futuresymbol映射到对应的option symbol .
option_dict = {
"IH": "上证50股指期权",
"IF": "沪深300股指期权",
"IC": "中证500股指期权",
"IM": "中证1000股指期权"
}
# 解析 future_symbol 获取期货代码和到期月份
m = re.match(r'([A-Za-z]+)(\d+)', future_symbol)
if not m:
raise ValueError(f"future_symbol 格式不正确: {future_symbol}")
future_code, future_end_month = m.groups()
option_symbol = option_dict.get(future_code)
return option_symbol, future_end_month
try:
option_symbol, future_end_month = get_option_symbol(future_symbol)
option_finance_board_df = ak.option_finance_board(symbol=option_symbol, end_month=future_end_month)
mask = option_finance_board_df['instrument'] == trade_option_symbol
if mask.any():
lastprice_value = option_finance_board_df.loc[mask, 'lastprice'].iloc[0]
return lastprice_value
# print(lastprice_value)
else:
print("未找到对应的行")
except Exception as e:
print(f"get_otm_option error for {future_symbol}: {e}")
return None
print("trade_df['symbol'].iloc[-1]}:", trade_df['symbol'].iloc[-1])
print("trade_df['symbol'].iloc[-1]}的类型:", type(trade_df['symbol'].iloc[-1]))
# 开多、空前置条件
开多条件 = (trade_df['趋势方向'].iloc[-1] == '多头趋势')
开空条件 = (trade_df['趋势方向'].iloc[-1] == '空头趋势')
if len(trade_df) >= 4*time_period:
#开多
开多1 = (trade_df['dj'].iloc[-1] >= 2) #max(0.8 * max(trade_df['dj'].iloc[-4*time_period-1:-1]), 10))
# print("开多1:",开多1)
开多2 = (trade_df['delta'].iloc[-1] >= 10)# max(0.8 * max(trade_df['delta'].iloc[-4*time_period-1:-1]), 350))
开多3 = (trade_df['delta累计'].iloc[-2] < 0 and trade_df['delta累计'].iloc[-1] > 0)
# 开空
开空1 = (trade_df['dj'].iloc[-1] <= -2) #min(0.8 * min(trade_df['dj'].iloc[-4*time_period-1:-1]), -10))
开空2 = (trade_df['delta'].iloc[-1] <= -10) #min(0.8 * min(trade_df['delta'].iloc[-4*time_period-1:-1]),-350))
# print("开空2:",开空2)
开空3 = (trade_df['delta累计'].iloc[-2] > 0 and trade_df['delta累计'].iloc[-1] < 0)
# 开多组合 = (开多条件 and (开多1 or 开多2 or 开多3))
# 开空组合 = (开空条件 and (开空1 or 开空2 or 开空3))
# 平多组合 = (开空条件 or 开空1 or 开空2 or 开空3)
# 平空组合 = (开多条件 or 开多1 or 开多2 or 开多3)
开多组合 = 开多1 and 开多2
开空组合 = 开空1 and 开空2
平多组合 = 开空1 or 开空2
平空组合 = 开多1 or 开多2
option_buy_symbol = ''
option_buy_price = 0
option_sell_symbol = ''
option_sell_price = 0
# 平空
if param.pos < 0 and 平空组合:
# close_sell_price = get_otm_pirce(data["InstrumentID"].decode(), option_sell_symbol)
print(
"平空: ",
"ExchangeID: ",
data["ExchangeID"],
"InstrumentID",
option_sell_symbol,
"AskPrice1",
800,#close_sell_price + param.py,
)
# 平空
self.insert_order(
data["ExchangeID"],
option_sell_symbol,
800,#close_sell_price + param.py,
param.Lots,
b"0",
b"1",
)
self.insert_order(
data["ExchangeID"],
option_sell_symbol,
800,#close_sell_price + param.py,
param.Lots,
b"0",
b"3",
)
param.pos = 0
param.sl_shor_price = 0
param.short_trailing_stop_price = 0
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"反手平空:",
"平仓价格:",
data['AskPrice1'] + param.py,
"堆积数:",
trade_df["dj"].iloc[-1],
)
self.save_to_csv(instrument_id)
# 发送邮件
# text = f"平空交易: 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 反手平空的平仓价格为{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
text = f"C_S_T: ID:{option_sell_symbol}, datetime:{trade_df['datetime'].iloc[-1]}, C_S_T_Price:{data['AskPrice1'] + param.py}, T_Lots:{param.Lots}"
send_mail(text)
# 开多
if param.pos == 0 and 开多组合:
print("trade_df_last:",trade_df['symbol'].iloc[-1])
option_buy_symbol,option_buy_price= get_otm_option(data["InstrumentID"].decode(), 'C')
print("买入看涨平值期权为:", option_buy_symbol, ",价格为:", option_buy_price)
print(
"开多: ",
"ExchangeID: ",
data["ExchangeID"],
"InstrumentID",
option_buy_symbol,
"AskPrice1",
option_buy_price + param.py,
)
# 开多
self.insert_order(
data["ExchangeID"],
option_buy_symbol,
option_buy_price + param.py,
param.Lots,
b"0",
b"0",
)
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"多头开仓",
"开仓价格:",
option_buy_price + param.py,
"堆积数:",
trade_df["dj"].iloc[-1],
)
param.pos = 1
param.long_trailing_stop_price = data["AskPrice1"]
param.sl_long_price = data["AskPrice1"]
self.save_to_csv(instrument_id)
# 发送邮件
text = f"O_L_T ID:{option_buy_symbol}, datetime:{trade_df['datetime'].iloc[-1]}, O_L_T_Price:{option_buy_price + param.py}, T_Lots:{param.Lots}"
send_mail(text)
# 平多
if param.pos > 0 and 平多组合:
print('option_buy_symbol',option_buy_symbol)
# close_buy_price = get_otm_pirce(data["InstrumentID"].decode(), option_buy_symbol)
# print('close_buy_price:',close_buy_price)
print(
"平多: ",
"ExchangeID: ",
data["ExchangeID"],
"InstrumentID",
option_buy_symbol,
"BidPrice1",
1,#close_buy_price - param.py,
)
# 平多
self.insert_order(
data["ExchangeID"],
option_buy_symbol,
1,#close_buy_price - param.py,
param.Lots,
b"1",
b"1",
)
self.insert_order(
data["ExchangeID"],
option_buy_symbol,
1,#close_buy_price - param.py,
param.Lots,
b"1",
b"3",
)
param.pos = 0
param.long_trailing_stop_price = 0
param.sl_long_price = 0
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"反手平多",
"平仓价格:",
data["BidPrice1"] - param.py,
"堆积数:",
trade_df["dj"].iloc[-1],
)
self.save_to_csv(instrument_id)
# 发送邮件
# text = f"平多交易: 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 反手平多的平仓价格{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
text = f"C_L_T: ID:{option_buy_symbol}, datetime:{trade_df['datetime'].iloc[-1]}, C_L_T_Price:{data['BidPrice1'] - param.py}, T_Lots:{param.Lots}"
send_mail(text)
# 开空
if param.pos == 0 and 开空组合:
option_sell_symbol,option_sell_price = get_otm_option(data["InstrumentID"].decode(), 'P')
print("买入看跌平值期权为:", option_sell_symbol, ",价格为:", option_sell_price)
print(
"开空: ",
"ExchangeID: ",
data["ExchangeID"],
"InstrumentID",
option_sell_symbol,
"BidPrice1",
data["BidPrice1"],
)
# 开空
self.insert_order(
data["ExchangeID"],
option_sell_symbol,
option_sell_price - param.py,
param.Lots,
b"1",
b"0",
)
print(
"datetime+sig: ",
trade_df["datetime"].iloc[-1],
"空头开仓",
"开仓价格:",
option_sell_price - param.py,
"堆积数:",
trade_df["dj"].iloc[-1],
)
param.pos = -1
param.short_trailing_stop_price = data["BidPrice1"]
param.sl_shor_price = data["BidPrice1"]
self.save_to_csv(instrument_id)
# 发送邮件
text = f"O_S_T: ID:{option_sell_symbol}, datetime:{trade_df['datetime'].iloc[-1]}, O_S_T_Price:{option_sell_price - param.py}, T_Lots:{param.Lots}"
send_mail(text)
print(trade_df)
symbol_label = trade_df["symbol"].iloc[-1]
trade_df.to_csv(f"trade_df_{symbol_label}.csv", index=False, encoding='utf-8')
# with open('trade_df.txt', 'w', encoding='utf-8') as file:
# print(trade_df, file=file)
print("------------------------------------------------")
# print(trade_df.iloc[0])
# print(trade_df.iloc[-1])
param.cont_df = len(trade_df)
except queue.Empty:
# print(f"当前合约队列为空,等待新数据插入。")
pass
# 将CTP推送的行情数据分发给对应线程队列去执行
def distribute_tick(self):
while True:
if self.status == 0:
data = None
while not self.md_queue.empty():
data = self.md_queue.get(block=False)
instrument_id = data["InstrumentID"].decode() # 品种代码
try:
self.queue_dict[instrument_id].put(
data, block=False
) # 往对应合约队列中插入行情
# print(f"{instrument_id}合约数据插入。")
except queue.Full:
# 当某个线程阻塞导致对应队列容量超限时抛出异常,不会影响其他合约的信号计算
print(
f"{instrument_id}合约信号计算阻塞导致对应队列已满,请检查对应代码逻辑后重启。"
)
else:
time.sleep(1)
def start(self, param_dict):
threads = []
self.param_dict = param_dict
for symbol in param_dict.keys():
# folder_path = "traderdata"
# ofdata_file_path = os.path.join("traderdata", f"{str(symbol)}_ofdata.csv")
if os.path.exists(f"traderdata/{symbol}_ofdata.csv"):
columns = [
"price",
"Ask",
"Bid",
"symbol",
"datetime",
"delta",
"close",
"open",
"high",
"low",
"volume",
"dj",
]
# import csv
# with open(f"traderdata/{symbol}_ofdata.csv", "r") as f:
# reader = csv.reader(f)
# for i, row in enumerate(reader, 1):
# if len(row) != 12:
# print(f"Line {i} has {len(row)} columns: {row}")
trade_dfs[symbol] = pd.read_csv(
f"traderdata/{symbol}_ofdata.csv", usecols=columns
)
else:
trade_dfs[symbol] = pd.DataFrame({})
self.queue_dict[symbol] = queue.Queue(
20
) # 为每个合约创建一个限制数为10的队列当计算发生阻塞导致队列达到限制数时会抛出异常
t = threading.Thread(
target=self.cal_sig, args=(self.queue_dict[symbol],)
) # 为每个合约单独创建一个线程计算开仓逻辑
threads.append(t)
t.start()
self.distribute_tick()
for t in threads:
t.join()
def run_trader(
param_dict,
broker_id,
td_server,
investor_id,
password,
app_id,
auth_code,
md_queue=None,
page_dir="",
private_resume_type=2,
public_resume_type=2,
):
my_trader = MyTrader(
broker_id,
td_server,
investor_id,
password,
app_id,
auth_code,
md_queue,
page_dir,
private_resume_type,
public_resume_type,
)
my_trader.start(param_dict)
if __name__ == "__main__":
# 注意运行前请先安装好algoplus,
# pip install AlgoPlus
# http://www.algo.plus/ctp/python/0103001.html
param_dict = {}
## 交易一个品种,手动设置合约代码
# param_dict["TF2509"] = ParamObj(
# symbol="TF2509",
# Lots=1,
# py=5,
# trailing_stop_percent=0.01,
# fixed_stop_loss_percent=0.02,
# dj_X=8,
# delta=500,
# sum_delta=800,
# 失衡=3,
# 堆积=3,
# 周期="2min",
# )
## 交易所有品种,自动设置合约代码,
# 交易指定品种时symbols = ['IM','IC','ag']
# symbols = ['IM','IC','ag']
symbols = contacts_df['品种代码'].tolist()
# for i, symbol in enumerate(symbols, start=1):
# globals()[f'sb_{i}'] = get_main_contact_on_time(symbol, contacts_df)
# symbol = globals()[f'sb_{i}']
# # print("最终使用的主连代码:",symbol)
# param_dict[str(symbol)] = ParamObj(symbol=symbol.encode('ascii'),Lots=1,py=5,trailing_stop_percent=0.01,fixed_stop_loss_percent=0.02,dj_X=8,delta=500,sum_delta=800,失衡=3,堆积=3,周期="5min")
for i, symbol in enumerate(symbols, start=1):
if symbol in ['wr', 'RS' , 'bb', 'WH', 'fb', 'rr', 'PL']:
continue
elif symbol in ['IM',]: #symbol in ['IH', 'IF', 'IC', 'IM', 'au', 'sc']
globals()[f'sb_{i}'] = get_main_contact_on_time(symbol, contacts_df)
symbol = globals()[f'sb_{i}']
param_dict[str(symbol)] = ParamObj(symbol=symbol.encode('ascii'),Lots=1,py=5,trailing_stop_percent=0.02,fixed_stop_loss_percent=0.04,dj_X=8,delta=500,sum_delta=800,失衡=3,堆积=3,周期="2min")
## 交易多个指定品种,自动设置合约代码,手动设置其他参数
# param_dict[symbol] = ParamObj(symbol=get_main_contact_on_time('IM', contacts_df),Lots=1,py=5,trailing_stop_percent=0.01,fixed_stop_loss_percent=0.02,dj_X=8,delta=500,sum_delta=800,失衡=3,堆积=3,周期="1min")
# param_dict[symbol] = ParamObj(symbol=get_main_contact_on_time('IC', contacts_df),Lots=1,py=5,trailing_stop_percent=0.02,fixed_stop_loss_percent=0.04,dj_X=8,delta=500,sum_delta=800,失衡=3,堆积=3,周期="1min")
# print(param_dict.keys())
# 用simnow模拟不要忘记屏蔽下方实盘的future_account字典
# SIMULATE_SERVER = {
# '电信1': {'BrokerID': 9999, 'TDServer': "180.168.146.187:10201", 'MDServer': '180.168.146.187:10211', 'AppID': 'simnow_client_test', 'AuthCode': '0000000000000000'},
# '电信2': {'BrokerID': 9999, 'TDServer': "180.168.146.187:10202", 'MDServer': '180.168.146.187:10212', 'AppID': 'simnow_client_test', 'AuthCode': '0000000000000000'},
# '移动': {'BrokerID': 9999, 'TDServer': "218.202.237.33:10203", 'MDServer': '218.202.237.33:10213', 'AppID': 'simnow_client_test', 'AuthCode': '0000000000000000'},
# 'TEST': {'BrokerID': 9999, 'TDServer': "180.168.146.187:10130", 'MDServer': '180.168.146.187:10131', 'AppID': 'simnow_client_test', 'AuthCode': '0000000000000000'},
# 'N视界': {'BrokerID': 10010, 'TDServer': "210.14.72.12:4600", 'MDServer': '210.14.72.12:4602', 'AppID': '', 'AuthCode': ''},
# }
# BrokerID统一为9999
# 支持上期所期权、能源中心期权、中金所期权、广期所期权、郑商所期权、大商所期权
# 第一组
# Trade Front180.168.146.187:10201Market Front180.168.146.187:10211【电信】看穿式前置使用监控中心生产秘钥
# 第二组
# Trade Front180.168.146.187:10202Market Front180.168.146.187:10212【电信】看穿式前置使用监控中心生产秘钥
# 第三组
# Trade Front218.202.237.33:10203Market Front218.202.237.33:10213【移动】看穿式前置使用监控中心生产秘钥
# 用户注册后默认的APPID为simnow_client_test认证码为000000000000000016个0默认开启终端认证程序化用户可以选择不开终端认证接入。
future_account = get_simulate_account(
investor_id="227508", # simnow账户注意是登录账户的IDSIMNOW个人首页查看
password="Zj1234!@#%", # simnow密码
server_name="电信1", # 电信1、电信2、移动、TEST、N视界
subscribe_list=list(param_dict.keys()), # 合约列表
)
# future_account = get_simulate_account(
# investor_id="00033556", # simnow账户注意是登录账户的IDSIMNOW个人首页查看
# password="27138169", # simnow密码
# server_name="N视界", # 电信1、电信2、移动、TEST、N视界
# subscribe_list=list(param_dict.keys()), # 合约列表
# )
# 实盘用这个不要忘记屏蔽上方simnow的future_account字典
# future_account = FutureAccount(
# broker_id='', # 期货公司BrokerID
# server_dict={'TDServer': "121.37.80.177:20002", 'MDServer': '121.37.80.177:20004'}, # TDServer为交易服务器MDServer为行情服务器。服务器地址格式为"ip:port。"
# reserve_server_dict={}, # 备用服务器地址
# investor_id='1114', # 账户
# password='123456', # 密码
# app_id='', # 认证使用AppID
# auth_code='', # 认证使用授权码
# subscribe_list=list(param_dict.keys()), # 订阅合约列表
# md_flow_path='./log', # MdApi流文件存储地址默认MD_LOCATION
# td_flow_path='./log', # TraderApi流文件存储地址默认TD_LOCATION
# )
# 实盘用这个不要忘记屏蔽上方simnow的future_account字典
# future_account = FutureAccount(
# broker_id='8888', # 期货公司BrokerID
# server_dict={'TDServer': "103.140.14.210:43205", 'MDServer': '103.140.14.210:43173'}, # TDServer为交易服务器MDServer为行情服务器。服务器地址格式为"ip:port。"
# reserve_server_dict={}, # 备用服务器地址
# investor_id='155878', # 账户
# password='Zj82334475', # 密码
# app_id='vntech_vnpy_2.0', # 认证使用AppID
# auth_code='N46EKN6TJ9U7V06V', # 认证使用授权码
# subscribe_list=list(param_dict.keys()), # 订阅合约列表
# md_flow_path='./log', # MdApi流文件存储地址默认MD_LOCATION
# td_flow_path='./log', # TraderApi流文件存储地址默认TD_LOCATION
# )
print("开始", len(future_account.subscribe_list))
# 共享队列
share_queue = Queue(maxsize=200)
# 行情进程
md_process = Process(target=run_tick_engine, args=(future_account, [share_queue]))
# 交易进程
trader_process = Process(
target=run_trader,
args=(
param_dict,
future_account.broker_id,
future_account.server_dict["TDServer"],
future_account.investor_id,
future_account.password,
future_account.app_id,
future_account.auth_code,
share_queue, # 队列
future_account.td_flow_path,
),
)
md_process.start()
trader_process.start()
md_process.join()
trader_process.join()