AI-Trader commited on
Commit
8ddd02c
1 Parent(s): 47ed6f2

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +128 -0
  2. requirements.txt +1 -0
  3. 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
+