Spaces:
Runtime error
Runtime error
Upload 3 files
Browse files- app.py +128 -0
- requirements.txt +1 -0
- utils.py +92 -0
app.py
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from utils import Kline_predict_plot, back_test_plot
|
3 |
+
|
4 |
+
|
5 |
+
with gr.Blocks() as generator:
|
6 |
+
with gr.Tab("English"):
|
7 |
+
gr.Markdown("# Available Markets: Stocks(Main China, HongKong, USA and so on) / Cryptocurrencies")
|
8 |
+
# gr.Markdown("Powered by AI")
|
9 |
+
with gr.Tab("Predictor"):
|
10 |
+
# gr.Markdown("Most 5 symbols at once can be put in `Symbols` box.")
|
11 |
+
once_max_num = 5
|
12 |
+
gr.Interface(
|
13 |
+
Kline_predict_plot,
|
14 |
+
[
|
15 |
+
gr.Dropdown(["model_predict_sk2", ], label="Predict Model", value='model_predict_sk2'),
|
16 |
+
gr.Textbox(label="Symbols", lines=1,
|
17 |
+
placeholder=f"Enter symbols(can't more than {once_max_num} at once), "
|
18 |
+
f"such as '000001.SH, btc-usd, AAPL, 18010.hk'",
|
19 |
+
),
|
20 |
+
gr.Textbox(label="Your Opinion", lines=2,
|
21 |
+
placeholder=f"Enter your base opinion for next trade day if you have("
|
22 |
+
f"such as 'I think it would be a big up and I would long absolutely' or "
|
23 |
+
f"'I shall sell a few'); or just leave here blank.",
|
24 |
+
),
|
25 |
+
gr.Dropdown(
|
26 |
+
["1hour", "1day", "1week", "1month"], label="Frequency Scale", value='1day', info="Kline scale."
|
27 |
+
),
|
28 |
+
gr.Slider(label="Feature Saturation", minimum=2, maximum=10, value=3, step=1),
|
29 |
+
gr.Slider(label="Sensitivity", minimum=2, maximum=20, value=5, step=1),
|
30 |
+
gr.Checkbox(label="Completed?", value=True, info="Is the latest bar completed?"),
|
31 |
+
gr.Slider(label="Show Bars", minimum=16, maximum=100, value=21, step=1),
|
32 |
+
gr.Number(label="Once Max", value=once_max_num, visible=False)
|
33 |
+
],
|
34 |
+
[
|
35 |
+
gr.Textbox(label=f"Ignored Symbols: not available,too new or more than {once_max_num} symbols."),
|
36 |
+
gr.Gallery(label="Bars Figure", show_label=True, columns=[1]),
|
37 |
+
],
|
38 |
+
examples=[
|
39 |
+
["model_predict_sk2", "000001.sh,600000.sh,000001.sz", "", "1day", 3, 5, True, 21, 5],
|
40 |
+
["model_predict_sk2", "aapl,goog", "There would be a big up, so long", "1week", 5, 15, True, 21, 5],
|
41 |
+
["model_predict_sk2", "btc-usd,eth-btc", "A big down is coming", "1day", 3, 3, False, 21, 5],
|
42 |
+
["model_predict_sk2", "btc-usd,000001.sh,1810.hk goog", "", "1day", 3, 10, False, 30, 5],
|
43 |
+
],
|
44 |
+
)
|
45 |
+
with gr.Tab("Back Tester"):
|
46 |
+
# gr.Markdown("Only 1 symbol at once can be put in `Symbols` box.")
|
47 |
+
gr.Interface(
|
48 |
+
back_test_plot,
|
49 |
+
[
|
50 |
+
gr.Dropdown(["model_predict_sk2", ], label="Predict Model", value='model_predict_sk2'),
|
51 |
+
gr.Textbox(label="Symbols", placeholder=f"Enter 1 Symbol, such as 'btc-usd'"),
|
52 |
+
gr.Dropdown(
|
53 |
+
["1hour", "1day", "1week", "1month"], label="Frequency Scale", value='1day', info="Kline scale."
|
54 |
+
),
|
55 |
+
gr.Slider(label="Feature Saturation", minimum=2, maximum=10, value=3, step=1),
|
56 |
+
gr.Slider(label="Sensitivity", minimum=2, maximum=20, value=5, step=1),
|
57 |
+
gr.Slider(label="Test Bars", minimum=10, maximum=200, value=100, step=1),
|
58 |
+
],
|
59 |
+
[gr.Gallery(label="Profit Figure", show_label=True, columns=[1])],
|
60 |
+
examples=[
|
61 |
+
["model_predict_sk2", "000001.sh", "1day", 3, 5, 20],
|
62 |
+
["model_predict_sk2", "btc-usd", "1day", 3, 10, 30],
|
63 |
+
["model_predict_sk2", "aapl", "1week", 5, 15, 80],
|
64 |
+
],
|
65 |
+
)
|
66 |
+
with gr.Tab("中文"):
|
67 |
+
gr.Markdown("# 可用市场: 股票(A股、港股、美股等) / 加密货币")
|
68 |
+
with gr.Tab("预测器"):
|
69 |
+
# gr.Markdown("`交易标的` 框中一次最多可同时输入5个标的")
|
70 |
+
once_max_num = 5
|
71 |
+
gr.Interface(
|
72 |
+
Kline_predict_plot,
|
73 |
+
[
|
74 |
+
gr.Dropdown(["model_predict_sk2", ], label="预测模型", value='model_predict_sk2'),
|
75 |
+
gr.Textbox(label="交易标的", lines=2,
|
76 |
+
placeholder=f"请输入要预测的交易标的(一次最多不能超过{once_max_num}个), "
|
77 |
+
f"例如输入: \"000001.SH, btc-usd, AAPL, 18010.hk\"",
|
78 |
+
),
|
79 |
+
gr.Textbox(label="主观观点", lines=2,
|
80 |
+
placeholder=f"请输入你的主观多空观点(例如输入: \"我认为后市会大涨,我要全仓做多\" 或者 "
|
81 |
+
f"\"我认为应该少量卖出一部分\"); 如果没有明确的多空观点,此处无需输入"),
|
82 |
+
gr.Dropdown(
|
83 |
+
["1hour", "1day", "1week", "1month"], label="K线级别", value='1day',
|
84 |
+
info="选择小时K线、日K线、周K线或者月K线"
|
85 |
+
),
|
86 |
+
gr.Slider(label="特征饱和度", minimum=2, maximum=10, value=3, step=1),
|
87 |
+
gr.Slider(label="敏感度", minimum=2, maximum=20, value=5, step=1),
|
88 |
+
gr.Checkbox(label="已完成?", value=True, info="最新的K线是否已经完成?"),
|
89 |
+
gr.Slider(label="展示K线数", minimum=16, maximum=100, value=21, step=1),
|
90 |
+
gr.Number(label="最多预测数", value=once_max_num, visible=False)
|
91 |
+
],
|
92 |
+
[
|
93 |
+
gr.Textbox(label=f"有误交易标的: 不可用、太新或者一次预测数大于{once_max_num}个"),
|
94 |
+
gr.Gallery(label="K线图", show_label=True, columns=[1]),
|
95 |
+
],
|
96 |
+
examples=[
|
97 |
+
["model_predict_sk2", "000001.sh,600000.sh,000001.sz", "", "1day", 3, 5, True, 21, 5],
|
98 |
+
["model_predict_sk2", "aapl,goog", "我认为后市会大涨,我要全仓做多", "1week", 5, 15, True, 21, 5],
|
99 |
+
["model_predict_sk2", "btc-usd,eth-btc", "后市很可能会大幅下跌", "1day", 3, 3, False, 21, 5],
|
100 |
+
["model_predict_sk2", "btc-usd,000001.sh,1810.hk goog", "", "1day", 3, 10, False, 30, 5],
|
101 |
+
],
|
102 |
+
)
|
103 |
+
with gr.Tab("回测器"):
|
104 |
+
# gr.Markdown("Only 1 symbol at once can be put in `Symbols` box.")
|
105 |
+
gr.Interface(
|
106 |
+
back_test_plot,
|
107 |
+
[
|
108 |
+
gr.Dropdown(["model_predict_sk2", ], label="预测模型", value='model_predict_sk2'),
|
109 |
+
gr.Textbox(label="交易标的", placeholder=f"请输入一个交易标的, 例如输入:\"btc-usd\""),
|
110 |
+
gr.Dropdown(
|
111 |
+
["1hour", "1day", "1week", "1month"], label="K线级别", value='1day',
|
112 |
+
info="选择小时K线、日K线、周K线或者月K线"
|
113 |
+
),
|
114 |
+
gr.Slider(label="特征饱和度", minimum=2, maximum=10, value=3, step=1),
|
115 |
+
gr.Slider(label="敏感度", minimum=2, maximum=20, value=5, step=1),
|
116 |
+
gr.Slider(label="回测K线数", minimum=10, maximum=200, value=100, step=1),
|
117 |
+
],
|
118 |
+
[gr.Gallery(label="回测曲线", show_label=True, columns=[1])],
|
119 |
+
examples=[
|
120 |
+
["model_predict_sk2", "000001.sh", "1day", 3, 5, 20],
|
121 |
+
["model_predict_sk2", "btc-usd", "1day", 3, 10, 30],
|
122 |
+
["model_predict_sk2", "aapl", "1week", 5, 15, 80],
|
123 |
+
],
|
124 |
+
)
|
125 |
+
|
126 |
+
|
127 |
+
generator.queue(max_size=1).launch()
|
128 |
+
|
requirements.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
mplfinance
|
utils.py
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import io
|
2 |
+
import os
|
3 |
+
import json
|
4 |
+
import requests
|
5 |
+
import pandas as pd
|
6 |
+
import mplfinance as mpf
|
7 |
+
import matplotlib.pyplot as plt
|
8 |
+
from PIL import Image
|
9 |
+
|
10 |
+
|
11 |
+
def generate_pil_img():
|
12 |
+
img_buf = io.BytesIO()
|
13 |
+
plt.savefig(img_buf, format='png')
|
14 |
+
return Image.open(img_buf)
|
15 |
+
|
16 |
+
|
17 |
+
def plot_Klines_fig(bars, code, precision=0.0001):
|
18 |
+
fig, axes = mpf.plot(bars, type='candle', mav=(5, 10), volume=True, title=f'\n{code}',
|
19 |
+
figsize=(12, 6), returnfig=True)
|
20 |
+
fixed_txt = 'Predict\nNext Bar'
|
21 |
+
for ci in ['Open', 'High', 'Low', 'Close', 'Volume']:
|
22 |
+
fixed_txt += f'\n{ci[0]}:{"{:.3e}".format(bars.iloc[-1][ci])}'
|
23 |
+
hl_chg = bars['High'].iloc[-1] / bars['Low'].iloc[-1] - 1.0
|
24 |
+
axes[0].annotate(fixed_txt, textcoords='axes fraction', xytext=(1.006, -0.37), color='r',
|
25 |
+
bbox=dict(facecolor='gray'),
|
26 |
+
xy=(len(bars) - 1, max(bars['Low'].min(), bars.iloc[-1]['Low'] * (1 - hl_chg / 4))),
|
27 |
+
arrowprops=dict(facecolor='r', width=5))
|
28 |
+
return generate_pil_img()
|
29 |
+
|
30 |
+
|
31 |
+
def plot_txt(text):
|
32 |
+
plt.figure(figsize=(12, 6))
|
33 |
+
plt.text(0.2, 0.8, text, size=12, alpha=0.8)
|
34 |
+
plt.axis('off')
|
35 |
+
return generate_pil_img()
|
36 |
+
|
37 |
+
|
38 |
+
def Kline_predict_plot(model_id, symbols, user_opinion, frequency, feature_saturation, sensitivity,
|
39 |
+
latest_bar_completed, show_bars, once_max):
|
40 |
+
params = {
|
41 |
+
'codes_str': symbols,
|
42 |
+
'user_opinion': user_opinion,
|
43 |
+
'frequency': frequency,
|
44 |
+
'feature_saturation': feature_saturation,
|
45 |
+
'latest_completed': latest_bar_completed,
|
46 |
+
'sensitivity': sensitivity,
|
47 |
+
'show_bars': show_bars,
|
48 |
+
'once_max': once_max,
|
49 |
+
}
|
50 |
+
headers = {'Content-Type': 'application/json'}
|
51 |
+
response = requests.post(os.environ[model_id] + 'predict', data=json.dumps(params), headers=headers)
|
52 |
+
result = response.json()
|
53 |
+
coins_not_available = result['codes_remove']
|
54 |
+
klines_data = result['klines_data']
|
55 |
+
figs = []
|
56 |
+
for codei, vi in klines_data.items():
|
57 |
+
bars = pd.DataFrame(vi)
|
58 |
+
bars.index = bars.index.map(pd.Timestamp)
|
59 |
+
figs.append(plot_Klines_fig(bars, codei))
|
60 |
+
return ','.join(coins_not_available) if len(coins_not_available) > 0 else 'No one', figs
|
61 |
+
|
62 |
+
|
63 |
+
def back_test_plot(model_id, symbols, frequency, feature_saturation, sensitivity, test_bars):
|
64 |
+
params = {
|
65 |
+
'codes_str': symbols,
|
66 |
+
'frequency': frequency,
|
67 |
+
'feature_saturation': feature_saturation,
|
68 |
+
'sensitivity': sensitivity,
|
69 |
+
'test_bars': test_bars,
|
70 |
+
}
|
71 |
+
headers = {'Content-Type': 'application/json'}
|
72 |
+
response = requests.post(os.environ[model_id] + 'back_test', data=json.dumps(params), headers=headers)
|
73 |
+
result = response.json()
|
74 |
+
test_result = result['test_result']
|
75 |
+
if isinstance(test_result, str):
|
76 |
+
return [plot_txt(test_result)]
|
77 |
+
else:
|
78 |
+
assert isinstance(test_result, dict), "`test_result` type is wrong."
|
79 |
+
keys_list = list(test_result.keys())
|
80 |
+
code, code_name = keys_list if len(keys_list[0]) < len(keys_list[1]) else keys_list[::-1]
|
81 |
+
labels, profits = pd.Series(test_result[code]), pd.Series(test_result[code_name])
|
82 |
+
labels.index, profits.index = labels.index.map(pd.Timestamp), profits.index.map(pd.Timestamp)
|
83 |
+
plt.figure()
|
84 |
+
(profits + 1.0).cumprod().plot(
|
85 |
+
label=f'profits => win_ratio:{round((profits > 0).mean() * 100, 2)}%')
|
86 |
+
(labels + 1.0).cumprod().plot(
|
87 |
+
label=f'{code} => up_ratio:{round((labels > 0).mean() * 100, 2)}%', linestyle='--')
|
88 |
+
plt.title(code_name)
|
89 |
+
plt.legend()
|
90 |
+
plt.grid()
|
91 |
+
return [generate_pil_img()]
|
92 |
+
|