添加实盘和模拟盘交易相关脚本和配置文件
- 新增实盘和模拟盘交易相关批处理脚本和Python脚本 - 添加交易数据记录和时间同步相关文件 - 包含交易策略、行情数据处理和定时任务脚本 - 新增交易品种和费率信息CSV文件
This commit is contained in:
1026
999.账户相关/simnow_trader/traderdata/IF2503_ofdata.csv
Normal file
1026
999.账户相关/simnow_trader/traderdata/IF2503_ofdata.csv
Normal file
File diff suppressed because it is too large
Load Diff
1026
999.账户相关/simnow_trader/traderdata/IH2503_ofdata.csv
Normal file
1026
999.账户相关/simnow_trader/traderdata/IH2503_ofdata.csv
Normal file
File diff suppressed because it is too large
Load Diff
1049
999.账户相关/simnow_trader/traderdata/IM2503_ofdata.csv
Normal file
1049
999.账户相关/simnow_trader/traderdata/IM2503_ofdata.csv
Normal file
File diff suppressed because it is too large
Load Diff
9
999.账户相关/simnow_trader/traderdata/IM2503_traderdata.csv
Normal file
9
999.账户相关/simnow_trader/traderdata/IM2503_traderdata.csv
Normal 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
|
||||
|
181
999.账户相关/simnow_trader/traderdata/akshare数据下载.ipynb
Normal file
181
999.账户相关/simnow_trader/traderdata/akshare数据下载.ipynb
Normal 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
|
||||
}
|
||||
199
999.账户相关/simnow_trader/traderdata/app.py
Normal file
199
999.账户相关/simnow_trader/traderdata/app.py
Normal 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) # 监听所有网络接口
|
||||
1054
999.账户相关/simnow_trader/traderdata/rb2505_ofdata.csv
Normal file
1054
999.账户相关/simnow_trader/traderdata/rb2505_ofdata.csv
Normal file
File diff suppressed because it is too large
Load Diff
1
999.账户相关/simnow_trader/traderdata/run.bat
Normal file
1
999.账户相关/simnow_trader/traderdata/run.bat
Normal file
@@ -0,0 +1 @@
|
||||
python app.py
|
||||
106
999.账户相关/simnow_trader/traderdata/templates/index.html
Normal file
106
999.账户相关/simnow_trader/traderdata/templates/index.html
Normal 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>
|
||||
199
999.账户相关/simnow_trader/traderdata/templates/index——test.html
Normal file
199
999.账户相关/simnow_trader/traderdata/templates/index——test.html
Normal 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>
|
||||
Reference in New Issue
Block a user