增加交易策略、交易指标、量化库代码等文件夹
This commit is contained in:
@@ -29,7 +29,6 @@ import re
|
||||
# import talib as tb
|
||||
|
||||
import akshare as ak
|
||||
import ast
|
||||
|
||||
# 加入邮件通知
|
||||
import smtplib
|
||||
@@ -110,42 +109,17 @@ clearing_time_dict = {
|
||||
|
||||
|
||||
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()
|
||||
global last_sent_time
|
||||
|
||||
# 检查时间间隔
|
||||
current_time = time.time()
|
||||
if current_time - last_sent_time < 60:
|
||||
print("current_time:",current_time)
|
||||
print("last_sent_time:",last_sent_time)
|
||||
print("一分钟内已发送过邮件,本次跳过")
|
||||
return # 直接退出,不执行发送
|
||||
msg = MIMEMultipart()
|
||||
msg["From"] = sender
|
||||
msg["To"] = ";".join(receivers)
|
||||
msg["Subject"] = subject
|
||||
html_content = f"""
|
||||
<html>
|
||||
<body>
|
||||
<p>以下是数据的最后一列:</p>
|
||||
{text}
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
msg.attach(MIMEText(html_content, 'html'))
|
||||
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 futures_main_day(future_symbol, delta_days):
|
||||
# 获取当前日期的数据
|
||||
today = datetime.now().strftime("%Y%m%d")
|
||||
@@ -157,78 +131,6 @@ def futures_main_day(future_symbol, delta_days):
|
||||
)
|
||||
return futures_main_sina_hist
|
||||
|
||||
def safe_literal_eval(x):
|
||||
"""带异常处理的安全转换"""
|
||||
try:
|
||||
return ast.literal_eval(x)
|
||||
except:
|
||||
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']
|
||||
|
||||
|
||||
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[i]
|
||||
else:
|
||||
# 应用递归公式
|
||||
us[i] = (1 - c1) * price[i] + (2 * c1 - c2) * price[i-1] \
|
||||
- (c1 + c3) * price[i-2] + c2 * us[i-1] + c3 * us[i-2]
|
||||
|
||||
us_new = np.around(us, decimals=2)
|
||||
ma_close = price.rolling(window=5*period).mean()
|
||||
|
||||
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] = '无趋势'
|
||||
|
||||
|
||||
return us_new,trend
|
||||
|
||||
# 交易程序---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
class ParamObj:
|
||||
@@ -687,24 +589,6 @@ class MyTrader(TraderApiBase):
|
||||
# 读取保留的模型数据CSV文件
|
||||
if os.path.exists(file_path):
|
||||
df = pd.read_csv(file_path)
|
||||
df = df.drop_duplicates(subset='datetime', keep='first').reset_index(drop=True)
|
||||
df = df[df['high'] != df['low']]
|
||||
df["delta"] = df["delta"].astype(float)
|
||||
df['datetime'] = pd.to_datetime(df['datetime'],format='mixed')#, dayfirst=True, format='mixed'
|
||||
df['delta累计'] = df.groupby(df['datetime'].dt.date)['delta'].cumsum()
|
||||
df = df.fillna('缺值')
|
||||
df['终极平滑值'],df['趋势方向'] = ultimate_smoother(df['close'],time_period)
|
||||
df['datetime'] = df['datetime'].dt.strftime("%Y-%m-%d %H:%M:%S")
|
||||
df['POC'] = add_poc_column(df)
|
||||
|
||||
time_period = 48
|
||||
|
||||
if len(df) >=5*time_period and (df['趋势方向'].iloc[-1] != df['趋势方向'].iloc[-2]):
|
||||
table_text = df.iloc[:,3:].tail(1).to_html(index=False) #price,Ask,Bid,symbol,datetime,delta,close,open,high,low,volume,dj
|
||||
send_mail(table_text)
|
||||
else:
|
||||
pass
|
||||
|
||||
if not df.empty and param.kgdata is True:
|
||||
# 选择最后一行数据
|
||||
# df = df._append(df.iloc[-1], ignore_index=True)
|
||||
@@ -842,15 +726,57 @@ class MyTrader(TraderApiBase):
|
||||
self.read_to_csv(instrument_id)
|
||||
if len(trade_df) > param.cont_df:
|
||||
# 检查文件是否存在
|
||||
csv_file_path = f"traderdata/{instrument_id}_ofdata.csv"
|
||||
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):
|
||||
#jerome :保存数增加'delta累计'、POC、、终极平滑值、趋势方向
|
||||
# 仅保存最后一行数据
|
||||
trade_df.tail(1).to_csv(
|
||||
csv_file_path, mode="a", header=False, index=False
|
||||
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:
|
||||
# 创建新文件并保存整个DataFrame
|
||||
# 如果文件不存在,直接写入新数据
|
||||
trade_df.to_csv(csv_file_path, index=False)
|
||||
|
||||
# 更新跟踪止损价格
|
||||
@@ -1382,8 +1308,8 @@ class MyTrader(TraderApiBase):
|
||||
|
||||
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"):
|
||||
# ofdata_file_path = os.path.join("traderdata", f"{str(symbol)}_{周期}_ofdata.csv")
|
||||
if os.path.exists(f"traderdata/{symbol}_{周期}_ofdata.csv"):
|
||||
columns = [
|
||||
"price",
|
||||
"Ask",
|
||||
@@ -1399,13 +1325,13 @@ class MyTrader(TraderApiBase):
|
||||
"dj",
|
||||
]
|
||||
# import csv
|
||||
# with open(f"traderdata/{symbol}_ofdata.csv", "r") as f:
|
||||
# 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
|
||||
f"traderdata/{symbol}_{周期}_ofdata.csv", usecols=columns
|
||||
)
|
||||
|
||||
else:
|
||||
@@ -1457,21 +1383,21 @@ if __name__ == "__main__":
|
||||
# http://www.algo.plus/ctp/python/0103001.html
|
||||
|
||||
param_dict = {}
|
||||
# param_dict["IM2503"] = ParamObj(
|
||||
# symbol="IM2503",
|
||||
# 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",
|
||||
# )
|
||||
# param_dict["IF2503"] = ParamObj(
|
||||
# symbol="IF2503",
|
||||
param_dict["IM2505"] = ParamObj(
|
||||
symbol="IM2505",
|
||||
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",
|
||||
)
|
||||
# param_dict["IF2505"] = ParamObj(
|
||||
# symbol="IF2505",
|
||||
# Lots=1,
|
||||
# py=5,
|
||||
# trailing_stop_percent=0.01,
|
||||
@@ -1481,10 +1407,10 @@ if __name__ == "__main__":
|
||||
# sum_delta=300,
|
||||
# 失衡=3,
|
||||
# 堆积=3,
|
||||
# 周期="5min",
|
||||
# 周期="2min",
|
||||
# )
|
||||
# param_dict["IH2503"] = ParamObj(
|
||||
# symbol="IH2503",
|
||||
# param_dict["IH2505"] = ParamObj(
|
||||
# symbol="IH2505",
|
||||
# Lots=1,
|
||||
# py=5,
|
||||
# trailing_stop_percent=0.01,
|
||||
@@ -1494,10 +1420,10 @@ if __name__ == "__main__":
|
||||
# sum_delta=300,
|
||||
# 失衡=3,
|
||||
# 堆积=3,
|
||||
# 周期="5min",
|
||||
# 周期="2min",
|
||||
# )
|
||||
# param_dict["rb2505"] = ParamObj(
|
||||
# symbol="rb2505",
|
||||
# param_dict["lh2505"] = ParamObj(
|
||||
# symbol="lh2505",
|
||||
# Lots=1,
|
||||
# py=5,
|
||||
# trailing_stop_percent=0.01,
|
||||
@@ -1507,21 +1433,34 @@ if __name__ == "__main__":
|
||||
# sum_delta=2000,
|
||||
# 失衡=3,
|
||||
# 堆积=3,
|
||||
# 周期="5min",
|
||||
# 周期="1min",
|
||||
# )
|
||||
# param_dict["ag2505"] = ParamObj(
|
||||
# symbol="ag2505",
|
||||
# Lots=1,
|
||||
# py=5,
|
||||
# trailing_stop_percent=0.01,
|
||||
# fixed_stop_loss_percent=0.02,
|
||||
# dj_X=8,
|
||||
# delta=1500,
|
||||
# sum_delta=2000,
|
||||
# 失衡=3,
|
||||
# 堆积=3,
|
||||
# 周期="2min",
|
||||
# )
|
||||
# param_dict["ni2505"] = ParamObj(
|
||||
# symbol="ni2505",
|
||||
# Lots=1,
|
||||
# py=5,
|
||||
# trailing_stop_percent=0.01,
|
||||
# fixed_stop_loss_percent=0.02,
|
||||
# dj_X=8,
|
||||
# delta=1500,
|
||||
# sum_delta=2000,
|
||||
# 失衡=3,
|
||||
# 堆积=3,
|
||||
# 周期="2min",
|
||||
# )
|
||||
param_dict["ag2504"] = ParamObj(
|
||||
symbol="ag2504",
|
||||
Lots=1,
|
||||
py=5,
|
||||
trailing_stop_percent=0.01,
|
||||
fixed_stop_loss_percent=0.02,
|
||||
dj_X=8,
|
||||
delta=1500,
|
||||
sum_delta=2000,
|
||||
失衡=3,
|
||||
堆积=3,
|
||||
周期="1min",
|
||||
)
|
||||
# 用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'},
|
||||
@@ -1544,7 +1483,7 @@ if __name__ == "__main__":
|
||||
# 用户注册后,默认的APPID为simnow_client_test,认证码为0000000000000000(16个0),默认开启终端认证,程序化用户可以选择不开终端认证接入。
|
||||
|
||||
future_account = get_simulate_account(
|
||||
investor_id="135858", # simnow账户,注意是登录账户的ID,SIMNOW个人首页查看
|
||||
investor_id="223828", # simnow账户,注意是登录账户的ID,SIMNOW个人首页查看
|
||||
password="Zj1234!@#%", # simnow密码
|
||||
server_name="电信1", # 电信1、电信2、移动、TEST、N视界
|
||||
subscribe_list=list(param_dict.keys()), # 合约列表
|
||||
|
||||
Reference in New Issue
Block a user