1oscon commited on
Commit
7c58c89
·
verified ·
1 Parent(s): e481850

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +147 -93
app.py CHANGED
@@ -1,126 +1,180 @@
1
  # -*- coding: utf-8 -*-
2
  import gradio as gr
3
  import asyncio
4
- import json
5
  import threading
 
6
  import time
7
  from datetime import datetime
8
 
9
- # 全局控制
 
10
  运行线程 = None
11
- 运行状态 = {"运行中": False, "净值": 1.0, "回撤": 0.0, "日志": []}
12
-
13
- def 启动模拟(合约, 周期, 参数json):
14
- global 运行线程, 运行状态
15
-
16
- if 运行状态["运行中"]:
17
- return "已有任务运行中", "", ""
18
-
19
- # 解析参数
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  try:
21
- 参数 = json.loads(参数json) if 参数json else {}
22
- except:
23
- return "参数JSON格式错误", "", ""
24
-
25
- # 启动异步任务
26
- def 运行任务():
27
  from 插件_引擎.多策略引擎 import 多策略引擎
28
  from 插件_交易.策略_自适应 import 自适应策略
29
-
 
 
 
30
  async def 主循环():
31
- 运行状态["运行中"] = True
32
- 运行状态["日志"] = []
33
-
34
- 引擎 = 多策略引擎()
35
  策略 = 自适应策略(f"{合约}_{周期}分", 参数)
36
- 引擎.注册策略(f"{合约}_{周期}", 策略, 合约, int(周期))
37
-
38
  try:
39
- await 引擎.启动([合约])
40
  except Exception as e:
41
- 运行状态["日志"].append(f"错误: {e}")
42
  finally:
43
- 运行状态["运行中"] = False
44
-
45
- asyncio.run(主循环())
46
-
47
- 运行线程 = threading.Thread(target=运行任务)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  运行线程.start()
49
-
50
- return "模拟启动成功", "", ""
51
 
52
  def 停止模拟():
53
- global 运行状态
54
- 运行状态["运行中"] = False
55
- return "已发送停止信号"
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  def 获取状态():
58
- 日志文本 = "\n".join(运行状态["日志"][-50:]) # 最近50条
59
- 状态文本 = f"运行中: {运行状态['运行中']} | 净值: {运行状态['净值']:.4f} | 回撤: {运行状态['回撤']:.2%}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  return 状态文本, 日志文本
61
 
62
- # 默认参数(你的60分钟V1参数)
63
- 默认参数 = {
64
- "ver": "v1",
65
- "adx_thr": 25,
66
- "atr_buf_tr": 0.05,
67
- "rsi_low": 30,
68
- "rsi_high": 70,
69
- "mr_stop_atr": 2.0,
70
- "trend_logic": "adx",
71
- "alloc_mode": "fixed"
72
- }
73
 
74
- # Gradio界面
75
- with gr.Blocks(title="模拟实盘") as demo:
76
- gr.Markdown("# 📈 加密货币模拟实盘交易")
77
-
78
  with gr.Row():
79
- with gr.Column():
80
- 合约输入 = gr.Textbox(
81
- label="合约ID",
82
- value="UXLINK-USDT-SWAP",
83
- placeholder="例: BTC-USDT-SWAP"
84
- )
85
- 周期选择 = gr.Radio(
86
- label="周期(分钟)",
87
- choices=["30", "60", "120", "240"],
88
- value="60"
89
- )
90
- 参数输入 = gr.Textbox(
91
- label="策略参数(JSON)",
92
- value=json.dumps(默认参数, indent=2),
93
- lines=10
94
- )
95
-
96
  with gr.Row():
97
  启动按钮 = gr.Button("🚀 启动模拟", variant="primary")
98
  停止按钮 = gr.Button("⏹️ 停止模拟", variant="stop")
99
-
100
- with gr.Column():
 
101
  状态显示 = gr.Textbox(label="运行状态", lines=1)
102
- 日志显示 = gr.Textbox(label="实时日志", lines=20)
103
- 刷新按钮 = gr.Button("🔄 刷新状态")
104
-
105
  # 事件绑定
106
- 启动按钮.click(
107
- fn=启动模拟,
108
- inputs=[合约输入, 周期选择, 参数输入],
109
- outputs=[状态显示, 日志显示, gr.Textbox(visible=False)]
110
- )
111
-
112
- 停止按钮.click(
113
- fn=停止模拟,
114
- outputs=状态显示
115
- )
116
-
117
- 刷新按钮.click(
118
- fn=获取状态,
119
- outputs=[状态显示, 日志显示]
120
- )
121
-
122
- # 自动刷新
123
- demo.load(获取状态, outputs=[状态显示, 日志显示], every=2)
124
 
125
  if __name__ == "__main__":
126
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
  # -*- coding: utf-8 -*-
2
  import gradio as gr
3
  import asyncio
 
4
  import threading
5
+ import json
6
  import time
7
  from datetime import datetime
8
 
9
+ # 全局状态
10
+ 引擎实例 = None
11
  运行线程 = None
12
+ 状态锁 = threading.Lock()
13
+ 运行状态 = {
14
+ "运行中": False,
15
+ "合约": "",
16
+ "周期": 0,
17
+ "净值": 1.0,
18
+ "回撤": 0.0,
19
+ "日志": []
20
+ }
21
+
22
+ # 默认参数(示例,可直接替换为你的最优参数JSON)
23
+ 默认参数 = {
24
+ "ver": "v1",
25
+ "adx_thr": 25,
26
+ "atr_buf_tr": 0.1,
27
+ "rsi_low": 30,
28
+ "rsi_high": 70,
29
+ "mr_stop_atr": 2.0,
30
+ "trend_logic": "adx",
31
+ "alloc_mode": "fixed"
32
+ }
33
+
34
+ def _记录(msg: str):
35
+ with 状态锁:
36
+ 运行状态["日志"].append(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")
37
+ # 控制日志长度
38
+ if len(运行状态["日志"]) > 500:
39
+ 运行状态["日志"] = 运行状态["日志"][-300:]
40
+
41
+ def _后台任务(合约: str, 周期: int, 参数: dict):
42
+ """
43
+ 后台线程任务:启动引擎并运行。此函数内开自己的事件循环。
44
+ """
45
+ global 引擎实例
46
  try:
 
 
 
 
 
 
47
  from 插件_引擎.多策略引擎 import 多策略引擎
48
  from 插件_交易.策略_自适应 import 自适应策略
49
+
50
+ loop = asyncio.new_event_loop()
51
+ asyncio.set_event_loop(loop)
52
+
53
  async def 主循环():
54
+ global 引擎实例
55
+ 引擎实例 = 多策略引擎()
 
 
56
  策略 = 自适应策略(f"{合约}_{周期}分", 参数)
57
+ 引擎实例.注册策略(f"{合约}_{周期}", 策略, 合约, int(周期))
58
+ _记录(f"引擎启动:{合约} / {周期} 分")
59
  try:
60
+ await 引擎实例.启动([合约])
61
  except Exception as e:
62
+ _记录(f"引擎异常:{e}")
63
  finally:
64
+ with 状态锁:
65
+ 运行状态["运行中"] = False
66
+ _记录("引擎结束")
67
+
68
+ loop.run_until_complete(主循环())
69
+ except Exception as e:
70
+ _记录(f"后台任务异常:{e}")
71
+ with 状态锁:
72
+ 运行状态["运行中"] = False
73
+
74
+ def 启动模拟(合约: str, 周期: str, 参数json: str):
75
+ """
76
+ 点击“启动模拟”时调用
77
+ """
78
+ global 运行线程
79
+ with 状态锁:
80
+ if 运行状态["运行中"]:
81
+ return f"已有任务运行中:{运行状态['合约']} / {运行状态['周期']}分", "\n".join(运行状态["日志"][-100:])
82
+
83
+ # 解析参数
84
+ if 参数json.strip():
85
+ try:
86
+ 参数 = json.loads(参数json)
87
+ except Exception as e:
88
+ return f"参数JSON格式错误:{e}", "\n".join(运行状态["日志"][-100:])
89
+ else:
90
+ 参数 = 默认参数
91
+
92
+ # 启动后台线程
93
+ try:
94
+ p = int(周期)
95
+ except:
96
+ return "周期必须是数字(30/60/120/240)", "\n".join(运行状态["日志"][-100:])
97
+
98
+ with 状态锁:
99
+ 运行状态["运行中"] = True
100
+ 运行状态["合约"] = 合约
101
+ 运行状态["周期"] = p
102
+ 运行状态["净值"] = 1.0
103
+ 运行状态["回撤"] = 0.0
104
+ 运行状态["日志"].clear()
105
+
106
+ _记录(f"准备启动:合约={合约} 周期={p} 参数={参数}")
107
+
108
+ 运行线程 = threading.Thread(target=_后台任务, args=(合约, p, 参数), daemon=True)
109
  运行线程.start()
110
+
111
+ return "模拟启动成功", "\n".join(运行状态["日志"][-100:])
112
 
113
  def 停止模拟():
114
+ """
115
+ 点击“停止模拟”时调用
116
+ 说明:这里只设置引擎停止处理信号(不强制关闭WS)。
117
+ """
118
+ global 引擎实例
119
+ if 引擎实例 is None:
120
+ return "当前没有运行中的任务"
121
+ try:
122
+ 引擎实例.停止()
123
+ _记录("已请求停止(引擎将不再处理新信号)")
124
+ return "已发送停止信��"
125
+ except Exception as e:
126
+ _记录(f"停止失败:{e}")
127
+ return f"停止失败:{e}"
128
 
129
  def 获取状态():
130
+ """
131
+ 定时器/“刷新状态”调用:读取净值、回撤、日志
132
+ """
133
+ with 状态锁:
134
+ # 从引擎里读净值/回撤(如果有)
135
+ try:
136
+ if 引擎实例 is not None and 引擎实例.交易所 is not None:
137
+ # 交易所.净值 会在引擎每根收盘时更新;此处只是读
138
+ nv = float(getattr(引擎实例.交易所, "净值", 1.0) or 1.0)
139
+ dd = float(getattr(引擎实例.交易所, "回撤", 0.0) or 0.0)
140
+ 运行状态["净值"] = nv
141
+ 运行状态["回撤"] = dd
142
+ except Exception as e:
143
+ _记录(f"读取状态失败:{e}")
144
+
145
+ 状态文本 = f"运行中: {运行状态['运行中']} | 合约: {运行状态['合约']} | 周期: {运行状态['周期']}m | 净值: {运行状态['净值']:.4f} | 回撤: {运行状态['回撤']:.2%}"
146
+ 日志文本 = "\n".join(运行状态["日志"][-120:])
147
  return 状态文本, 日志文本
148
 
149
+ # Gradio 界面
150
+ with gr.Blocks(title="模拟实盘(OKX 公共WS + 多策略引擎)") as demo:
151
+ gr.Markdown("# 📈 模拟实盘(订阅OKX公共行情 → 聚合K线 → 策略 → 纸上交易所)")
152
+ gr.Markdown("提示:此为演示用。停止按钮仅令引擎停止处理新信号,WebSocket仍保持连接,避免强制断开导致报错。")
 
 
 
 
 
 
 
153
 
 
 
 
 
154
  with gr.Row():
155
+ with gr.Column(scale=1):
156
+ 合约输入 = gr.Textbox(label="合约ID", value="UXLINK-USDT-SWAP", placeholder="例:BTC-USDT-SWAP / ETH-USDT-SWAP")
157
+ 周期选择 = gr.Radio(label="周期(分钟)", choices=["30", "60", "120", "240"], value="60")
158
+ 参数输入 = gr.Textbox(label="策略参数(JSON)", value=json.dumps(默认参数, ensure_ascii=False, indent=2), lines=12)
159
+
 
 
 
 
 
 
 
 
 
 
 
 
160
  with gr.Row():
161
  启动按钮 = gr.Button("🚀 启动模拟", variant="primary")
162
  停止按钮 = gr.Button("⏹️ 停止模拟", variant="stop")
163
+ 刷新按钮 = gr.Button("🔄 刷新状态")
164
+
165
+ with gr.Column(scale=1):
166
  状态显示 = gr.Textbox(label="运行状态", lines=1)
167
+ 日志显示 = gr.Textbox(label="实时日志(最近120行)", lines=22)
168
+
 
169
  # 事件绑定
170
+ 启动按钮.click(fn=启动模拟, inputs=[合约输入, 周期选择, 参数输入], outputs=[状态显示, 日志显示])
171
+ 停止按钮.click(fn=停止模拟, outputs=状态显示)
172
+ 刷新按钮.click(fn=获取状态, outputs=[状态显示, 日志显示])
173
+
174
+ # 页面加载时刷新一次
175
+ demo.load(获取状态, outputs=[状态显示, 日志显示])
176
+ # Gradio 4:用 Timer 每2秒刷新
177
+ gr.Timer(2.0, fn=获取状态, outputs=[状态显示, 日志显示])
 
 
 
 
 
 
 
 
 
 
178
 
179
  if __name__ == "__main__":
180
  demo.launch(server_name="0.0.0.0", server_port=7860)