添加实盘和模拟盘交易相关脚本和配置文件

- 新增实盘和模拟盘交易相关批处理脚本和Python脚本
- 添加交易数据记录和时间同步相关文件
- 包含交易策略、行情数据处理和定时任务脚本
- 新增交易品种和费率信息CSV文件
This commit is contained in:
2025-03-02 18:59:58 +08:00
parent e449354b69
commit b814dfe535
30 changed files with 26345 additions and 63 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
datetime,pos,short_trailing_stop_price,long_trailing_stop_price,sl_long_price,sl_shor_price
2025-02-26 11:00:00,1,0,6426.8,6426.8,0
2025-02-26 11:20:00,0,0.0,0,0,0.0
2025-02-26 14:15:00,1,0.0,6413.6,6413.6,0.0
2025-02-26 14:55:00,0,0.0,0,0,0.0
2025-02-27 14:50:00,1,0.0,6406.0,6406.0,0.0
2025-02-27 14:55:00,0,0.0,0,0,0.0
2025-02-28 09:35:00,-1,6351.6,0.0,0.0,6351.6
2025-02-28 14:55:00,0,0,0.0,0.0,0
1 datetime pos short_trailing_stop_price long_trailing_stop_price sl_long_price sl_shor_price
2 2025-02-26 11:00:00 1 0 6426.8 6426.8 0
3 2025-02-26 11:20:00 0 0.0 0 0 0.0
4 2025-02-26 14:15:00 1 0.0 6413.6 6413.6 0.0
5 2025-02-26 14:55:00 0 0.0 0 0 0.0
6 2025-02-27 14:50:00 1 0.0 6406.0 6406.0 0.0
7 2025-02-27 14:55:00 0 0.0 0 0 0.0
8 2025-02-28 09:35:00 -1 6351.6 0.0 0.0 6351.6
9 2025-02-28 14:55:00 0 0 0.0 0.0 0

View File

@@ -0,0 +1,181 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import akshare as ak\n",
"import pandas as pd\n",
"import numpy as np\n",
"import os\n",
"import ast\n",
"import time"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"symbol_name = 'rb2505'\n",
"# 获取当前工作目录\n",
"current_directory = os.getcwd()\n",
"print(\"当前工作目录:\", current_directory)\n",
"# 设置新的工作目录\n",
"new_directory = \"C:/Users/zhouj/Desktop\"\n",
"os.chdir(new_directory) \n",
"# 验证新的工作目录\n",
"updated_directory = os.getcwd()\n",
"print(\"已更改为新的工作目录:\", updated_directory)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"futures_zh_minute_sina_df = ak.futures_zh_minute_sina(symbol=symbol_name, period=\"5\")\n",
"print(futures_zh_minute_sina_df)\n",
"\n",
"df = pd.read_csv(f\"{symbol_name}_ofdata.csv\", usecols=range(12))\n",
"df.tail(1)\n",
"\n",
"def ultimate_smoother(price, period):\n",
" # 初始化变量(修正角度单位为弧度)\n",
" a1 = np.exp(-1.414 * np.pi / period)\n",
" b1 = 2 * a1 * np.cos(1.414 * np.pi / period) # 将180改为np.pi\n",
" c2 = b1\n",
" c3 = -a1**2\n",
" c1 = (1 + c2 - c3) / 4\n",
"\n",
" # 准备输出序列\n",
" us = np.zeros(len(price))\n",
" us_new = np.zeros(len(price))\n",
" trend = [None] * (len(price))\n",
" ma_close = np.zeros(len(price))\n",
"\n",
" # 前4个点用原始价格初始化\n",
" for i in range(len(price)):\n",
" if i < 4:\n",
" us[i] = price[i]\n",
" else:\n",
" # 应用递归公式\n",
" us[i] = (1 - c1) * price[i] + (2 * c1 - c2) * price[i-1] \\\n",
" - (c1 + c3) * price[i-2] + c2 * us[i-1] + c3 * us[i-2]\n",
"\n",
" us_new = np.around(us, decimals=2)\n",
" ma_close = price.rolling(window=5 * period).mean()\n",
"\n",
" if us_new[i] > price[i] and ma_close[i] > price[i]:\n",
" trend[i] = '空头趋势'\n",
" elif us_new[i] < price[i] and ma_close[i] < price[i]:\n",
" trend[i] = '多头趋势'\n",
" else:\n",
" trend[i] = '无趋势'\n",
"\n",
" return us_new, trend"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"futures_zh_minute_sina_df['datetime'] = pd.to_datetime(futures_zh_minute_sina_df['datetime'])\n",
"futures_zh_minute_sina_df['终极平滑值'], futures_zh_minute_sina_df[\n",
" '趋势方向'] = ultimate_smoother(futures_zh_minute_sina_df[\"close\"], 48)\n",
"\n",
"# 设置索引\n",
"df['datetime'] = pd.to_datetime(df['datetime'])\n",
"df = df.set_index('datetime')\n",
"futures_zh_minute_sina_df = futures_zh_minute_sina_df.set_index('datetime')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_new = futures_zh_minute_sina_df.join(df[['price', 'Ask', 'Bid', 'delta','dj']], how='left')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_new['symbol'] = symbol_name\n",
"df_new = df_new.reset_index()\n",
"cols = [\n",
" 'price', 'Ask', 'Bid', 'symbol', 'datetime', 'delta', 'close', 'open',\n",
" 'high', 'low', 'volume', 'hold', 'dj', '终极平滑值', '趋势方向'\n",
"]\n",
"df_new = df_new[cols]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_new.head(5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_new.tail(5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"del df_new['hold'],df_new['终极平滑值'],df_new['趋势方向']"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df_new.to_csv(f\"{symbol_name}_ofdata_new.csv\", index=False)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -0,0 +1,199 @@
from flask import Flask, render_template, jsonify
import pandas as pd
import numpy as np
import os
import ast
import time
app = Flask(__name__)
# 加入邮件通知
import smtplib
from email.mime.text import MIMEText # 导入 MIMEText 类发送纯文本邮件
from email.mime.multipart import (
MIMEMultipart,
)
import akshare as ak
# 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设置发送邮件的邮箱密码或授权码
last_sent_time = 0
time_period = 60
# current_dir = os.path.dirname(os.path.abspath(__file__))
# os.chdir(current_dir)
# print("已更改为新的工作目录:", current_dir)
# 获取当前工作目录
current_directory = os.getcwd()
print("当前工作目录:", current_directory)
# 设置新的工作目录
new_directory = "C:/simnow_trader/traderdata"
os.chdir(new_directory)
# 验证新的工作目录
updated_directory = os.getcwd()
print("已更改为新的工作目录:", updated_directory)
# 获取当前文件夹中所有包含"ofdata"字符的CSV文件
def get_csv_files():
files = {}
for filename in os.listdir():
if "ofdata" in filename and filename.endswith(".csv"):
files[filename] = os.path.join(os.getcwd(), filename)
return files
def send_mail(text):
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'))
smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
smtp.login(username, password)
smtp.sendmail(sender, receivers, msg.as_string())
smtp.quit()
# 根据文件路径加载数据只读取前12列
def load_data(file_path):
df = pd.read_csv(file_path, usecols=range(12)) # 只读取前12列
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)
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
return df.iloc[-60:].to_dict(orient="records")
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
@app.route("/")
def index():
files = get_csv_files() # 获取所有符合条件的文件
# 默认显示第一个文件的数据
first_file = list(files.keys())[0] if files else None
data = load_data(files[first_file]) if first_file else []
return render_template("index.html", data=data, files=files, file_name=first_file)
@app.route("/data/<file_name>")
def switch_data(file_name):
files = get_csv_files() # 获取所有符合条件的文件
if file_name in files:
data = load_data(files[file_name])
return jsonify(data)
return jsonify({"error": "File not found"}), 404
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000, debug=True) # 监听所有网络接口

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
python app.py

View File

@@ -0,0 +1,106 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>订单流实时数据监控</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.5/css/dataTables.bootstrap5.min.css">
<style>
table {
width: 100%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 8px;
text-align: center;
}
button {
margin: 10px;
padding: 10px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>Real-Time CSV Data Viewer</h1>
<!-- 动态生成按钮 -->
{% for file_name, file_path in files.items() %}
<button onclick="loadData('{{ file_name }}')">{{ file_name }}</button>
{% endfor %}
<h3>Data for {{ file_name }}</h3>
<table id="data-table">
<thead>
<tr>
<th>Symbol</th>
<th>Datetime</th>
<th>Delta</th>
<th>Close</th>
<th>Open</th>
<th>High</th>
<th>Low</th>
<th>Volume</th>
<th>DJ</th>
<th>Delta累计</th>
<th>POC</th>
<th>终极平滑值</th>
<th>趋势方向</th>
</tr>
</thead>
<tbody>
{% for row in data %}
<tr>
<td>{{ row.symbol }}</td>
<td>{{ row.datetime }}</td>
<td>{{ row.delta }}</td>
<td>{{ row.close }}</td>
<td>{{ row.open }}</td>
<td>{{ row.high }}</td>
<td>{{ row.low }}</td>
<td>{{ row.volume }}</td>
<td>{{ row.dj }}</td>
<td>{{ row.delta累计 }}</td>
<td>{{ row.POC }}</td>
<td>{{ row.终极平滑值 }}</td>
<td>{{ row.趋势方向 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
function loadData(fileName) {
fetch('/data/' + fileName)
.then(response => response.json())
.then(data => {
let tableBody = document.querySelector("#data-table tbody");
tableBody.innerHTML = ''; // 清空现有数据行
data.forEach(row => {
let rowElement = document.createElement('tr');
rowElement.innerHTML = `
<td>${row.symbol}</td>
<td>${row.datetime}</td>
<td>${row.delta}</td>
<td>${row.close}</td>
<td>${row.open}</td>
<td>${row.high}</td>
<td>${row.low}</td>
<td>${row.volume}</td>
<td>${row.dj}</td>
<td>${row.delta累计}</td>
<td>${row.POC}</td>
<td>${row.终极平滑值}</td>
<td>${row.趋势方向}</td>
`;
tableBody.appendChild(rowElement);
});
});
}
</script>
</body>
</html>

View File

@@ -0,0 +1,199 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSV Data Viewer</title>
<style>
table {
width: 100%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 8px;
text-align: center;
}
button {
margin: 10px;
padding: 10px;
cursor: pointer;
}
select {
width: 100%;
padding: 5px;
text-align: center;
}
</style>
</head>
<body>
<h1>Real-Time CSV Data Viewer</h1>
<!-- 动态生成文件切换按钮 -->
{% for file_name, file_path in files.items() %}
<button onclick="loadData('{{ file_name }}')">{{ file_name }}</button>
{% endfor %}
<h3>Data for {{ file_name }}</h3>
<table id="data-table">
<thead>
<tr>
<th>
<select id="filter-price" onchange="filterTable()">
<option value="">Price</option>
</select>
</th>
<th>
<select id="filter-Ask" onchange="filterTable()">
<option value="">Ask</option>
</select>
</th>
<th>
<select id="filter-Bid" onchange="filterTable()">
<option value="">Bid</option>
</select>
</th>
<th>
<select id="filter-symbol" onchange="filterTable()">
<option value="">Symbol</option>
</select>
</th>
<th>
<select id="filter-datetime" onchange="filterTable()">
<option value="">Datetime</option>
</select>
</th>
<th>
<select id="filter-delta" onchange="filterTable()">
<option value="">Delta</option>
</select>
</th>
<th>
<select id="filter-close" onchange="filterTable()">
<option value="">Close</option>
</select>
</th>
<th>
<select id="filter-open" onchange="filterTable()">
<option value="">Open</option>
</select>
</th>
<th>
<select id="filter-high" onchange="filterTable()">
<option value="">High</option>
</select>
</th>
<th>
<select id="filter-low" onchange="filterTable()">
<option value="">Low</option>
</select>
</th>
<th>
<select id="filter-volume" onchange="filterTable()">
<option value="">Volume</option>
</select>
</th>
<th>
<select id="filter-dj" onchange="filterTable()">
<option value="">DJ</option>
</select>
</th>
</tr>
</thead>
<tbody>
{% for row in data %}
<tr>
<td>{{ row.price }}</td>
<td>{{ row.Ask }}</td>
<td>{{ row.Bid }}</td>
<td>{{ row.symbol }}</td>
<td>{{ row.datetime }}</td>
<td>{{ row.delta }}</td>
<td>{{ row.close }}</td>
<td>{{ row.open }}</td>
<td>{{ row.high }}</td>
<td>{{ row.low }}</td>
<td>{{ row.volume }}</td>
<td>{{ row.dj }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
function loadData(fileName) {
fetch('/data/' + fileName)
.then(response => response.json())
.then(data => {
let tableBody = document.querySelector("#data-table tbody");
tableBody.innerHTML = ''; // 清空现有数据行
data.forEach(row => {
let rowElement = document.createElement('tr');
rowElement.innerHTML = `
<td>${row.price}</td>
<td>${row.Ask}</td>
<td>${row.Bid}</td>
<td>${row.symbol}</td>
<td>${row.datetime}</td>
<td>${row.delta}</td>
<td>${row.close}</td>
<td>${row.open}</td>
<td>${row.high}</td>
<td>${row.low}</td>
<td>${row.volume}</td>
<td>${row.dj}</td>
`;
tableBody.appendChild(rowElement);
});
populateFilters(data);
});
}
function populateFilters(data) {
let columns = ["price", "Ask", "Bid", "symbol", "datetime", "delta", "close", "open", "high", "low", "volume", "dj"];
columns.forEach(col => {
let uniqueValues = [...new Set(data.map(row => row[col]))];
let select = document.getElementById(`filter-${col}`);
select.innerHTML = '<option value="">All</option>';
uniqueValues.forEach(value => {
select.innerHTML += `<option value="${value}">${value}</option>`;
});
});
}
function filterTable() {
let filters = {
price: document.getElementById("filter-price").value,
Ask: document.getElementById("filter-Ask").value,
Bid: document.getElementById("filter-Bid").value,
symbol: document.getElementById("filter-symbol").value,
datetime: document.getElementById("filter-datetime").value,
delta: document.getElementById("filter-delta").value,
close: document.getElementById("filter-close").value,
open: document.getElementById("filter-open").value,
high: document.getElementById("filter-high").value,
low: document.getElementById("filter-low").value,
volume: document.getElementById("filter-volume").value,
dj: document.getElementById("filter-dj").value
};
let rows = document.querySelectorAll("#data-table tbody tr");
rows.forEach(row => {
let cells = row.children;
let show = true;
Object.keys(filters).forEach((col, index) => {
if (filters[col] && cells[index].textContent !== filters[col]) {
show = false;
}
});
row.style.display = show ? "" : "none";
});
}
</script>
</body>
</html>