Skip to content

Commit 31b8aba

Browse files
committed
init
0 parents commit 31b8aba

File tree

18 files changed

+871
-0
lines changed

18 files changed

+871
-0
lines changed

.gitignore

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
*.h5
2+
*.ipynb
3+
.pytest_cache/
4+
.vscode/
5+
tests/unused/*
6+
# Byte-compiled / optimized / DLL files
7+
__pycache__/
8+
*.py[cod]
9+
*$py.class
10+
.idea/
11+
# C extensions
12+
*.so
13+
14+
# Distribution / packaging
15+
.Python
16+
env/
17+
build/
18+
develop-eggs/
19+
dist/
20+
downloads/
21+
eggs/
22+
.eggs/
23+
lib/
24+
lib64/
25+
parts/
26+
sdist/
27+
var/
28+
*.egg-info/
29+
.installed.cfg
30+
*.egg
31+
32+
# PyInstaller
33+
# Usually these files are written by a python script from a template
34+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
35+
*.manifest
36+
*.spec
37+
38+
# Installer logs
39+
pip-log.txt
40+
pip-delete-this-directory.txt
41+
42+
# Unit test / coverage reports
43+
htmlcov/
44+
.tox/
45+
.coverage
46+
.coverage.*
47+
.cache
48+
nosetests.xml
49+
coverage.xml
50+
*,cover
51+
.hypothesis/
52+
53+
# Translations
54+
*.mo
55+
*.pot
56+
57+
# Django stuff:
58+
*.log
59+
local_settings.py
60+
61+
# Flask instance folder
62+
instance/
63+
64+
# Scrapy stuff:
65+
.scrapy
66+
67+
# Sphinx documentation
68+
docs/_build/
69+
70+
# PyBuilder
71+
target/
72+
73+
# IPython Notebook
74+
.ipynb_checkpoints
75+
76+
# pyenv
77+
.python-version
78+
79+
# celery beat schedule file
80+
celerybeat-schedule
81+
82+
# dotenv
83+
.env
84+
85+
# virtualenv
86+
venv/
87+
ENV/
88+
89+
# Spyder project settings
90+
.spyderproject
91+
92+
# Rope project settings
93+
.ropeproject
94+
95+
# =========================
96+
# Operating System Files
97+
# =========================
98+
99+
# OSX
100+
# =========================
101+
102+
.DS_Store
103+
.AppleDouble
104+
.LSOverride
105+
106+
# Thumbnails
107+
._*
108+
109+
# Files that might appear in the root of a volume
110+
.DocumentRevisions-V100
111+
.fseventsd
112+
.Spotlight-V100
113+
.TemporaryItems
114+
.Trashes
115+
.VolumeIcon.icns
116+
117+
# Directories potentially created on remote AFP share
118+
.AppleDB
119+
.AppleDesktop
120+
Network Trash Folder
121+
Temporary Items
122+
.apdisk
123+
124+
# Windows
125+
# =========================
126+
127+
# Windows image file caches
128+
Thumbs.db
129+
ehthumbs.db
130+
131+
# Folder config file
132+
Desktop.ini
133+
134+
# Recycle Bin used on file shares
135+
$RECYCLE.BIN/
136+
137+
# Windows Installer files
138+
*.cab
139+
*.msi
140+
*.msm
141+
*.msp
142+
143+
# Windows shortcuts
144+
*.lnk

backtrader_app.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import datetime
2+
3+
import akshare as ak
4+
import backtrader as bt
5+
import backtrader.analyzers as btanalyzers
6+
import pandas as pd
7+
import streamlit as st
8+
import yaml
9+
from streamlit_echarts import st_pyecharts
10+
11+
from charts import draw_pro_kline, draw_result_bar
12+
from frames import akshare_selector_ui, backtrader_selector_ui, params_selector_ui
13+
from modules.schemas import StrategyBase
14+
15+
# from utils.logs import LOGGER
16+
17+
18+
st.set_page_config(page_title="backtrader")
19+
20+
21+
def main():
22+
ak_params = akshare_selector_ui()
23+
backtrader_params = backtrader_selector_ui()
24+
if ak_params["symbol"]:
25+
stock_df = gen_stock_df(ak_params)
26+
27+
st.subheader("Kline")
28+
# kline = draw_pro_kline(stock_df)
29+
# st_pyecharts(kline, height="500px")
30+
31+
st.subheader("Strategy")
32+
name = st.selectbox("strategy", list(strategys.keys()))
33+
submitted, params = params_selector_ui(strategys[name])
34+
if submitted:
35+
backtrader_params.update(
36+
{
37+
"stock_df": stock_df.iloc[:, :6],
38+
"strategy": StrategyBase(name=name, params=params),
39+
}
40+
)
41+
par_df = run_backtrader(**backtrader_params)
42+
st.dataframe(par_df.style.highlight_max(subset=par_df.columns[-3:]))
43+
bar = draw_result_bar(par_df)
44+
st_pyecharts(bar, height="500px")
45+
46+
47+
@st.cache(allow_output_mutation=True)
48+
def gen_stock_df(ak_params: dict) -> pd.DataFrame:
49+
"""generate stock data
50+
51+
:param ak_params: dict.
52+
:return: pd.DataFrame.
53+
"""
54+
return ak.stock_zh_a_hist(**ak_params)
55+
56+
57+
@st.cache
58+
def run_backtrader(
59+
stock_df: pd.DataFrame,
60+
start_date: datetime.datetime,
61+
end_date: datetime.datetime,
62+
start_cash: int,
63+
commission_fee: float,
64+
stake: int,
65+
strategy: StrategyBase,
66+
) -> pd.DataFrame:
67+
"""run backtrader
68+
69+
:param stock_df: pd.DataFrame. stock data
70+
:param start_date: datetime.datetime. back trader from date
71+
:param end_date: datetime.datetime. back trader end date
72+
:param start_cash: int. back trader start cash
73+
:param commission_fee: float. commission fee
74+
:param stake: int. stake
75+
:param strategy: StrategyBase. strategy name an params
76+
:return: None.
77+
"""
78+
cerebro = bt.Cerebro()
79+
stock_df.columns = [
80+
"date",
81+
"open",
82+
"close",
83+
"high",
84+
"low",
85+
"volume",
86+
]
87+
stock_df.index = pd.to_datetime(stock_df["date"])
88+
data = bt.feeds.PandasData(dataname=stock_df, fromdate=start_date, todate=end_date)
89+
cerebro.adddata(data)
90+
cerebro.broker.setcash(start_cash)
91+
cerebro.broker.setcommission(commission=commission_fee)
92+
cerebro.addsizer(bt.sizers.FixedSize, stake=stake)
93+
cerebro.addanalyzer(btanalyzers.SharpeRatio, _name="sharpe")
94+
cerebro.addanalyzer(btanalyzers.DrawDown, _name="drawdown")
95+
cerebro.addanalyzer(btanalyzers.Returns, _name="returns")
96+
97+
print("start cash: %.2f" % cerebro.broker.getvalue())
98+
strategy_cli = getattr(__import__(f"strategy"), f"{strategy.name}Strategy")
99+
cerebro.optstrategy(strategy_cli, **strategy.params)
100+
back = cerebro.run()
101+
par_list = []
102+
for x in back:
103+
par = []
104+
for param in strategy.params.keys():
105+
par.append(x[0].params._getkwargs()[param])
106+
par.extend(
107+
[
108+
x[0].analyzers.returns.get_analysis()["rnorm100"],
109+
x[0].analyzers.drawdown.get_analysis()["max"]["drawdown"],
110+
x[0].analyzers.sharpe.get_analysis()["sharperatio"],
111+
]
112+
)
113+
par_list.append(par)
114+
columns = list(strategy.params.keys())
115+
columns.extend(["return", "dd", "sharpe"])
116+
par_df = pd.DataFrame(par_list, columns=columns)
117+
print("end cash: %.2f" % cerebro.broker.getvalue())
118+
return par_df
119+
120+
121+
def load_strategys(yaml_file):
122+
with open(yaml_file, "r") as f:
123+
strategys = yaml.safe_load(f)
124+
return strategys
125+
126+
127+
strategys = load_strategys("./config/strategy.yaml")
128+
129+
if __name__ == "__main__":
130+
main()

charts/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .results import draw_result_bar
2+
from .stock import draw_pro_kline
3+
4+
__all__ = ["draw_pro_kline", "draw_result_bar"]

charts/results.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import pandas as pd
2+
from pyecharts import options as opts
3+
from pyecharts.charts import Bar
4+
5+
6+
def draw_result_bar(df: pd.DataFrame, n_scors=3):
7+
params_columns = df.columns[:-n_scors]
8+
scores_columns = df.columns[-n_scors:]
9+
x_data = (
10+
df[params_columns]
11+
.apply(
12+
lambda x: "\n".join(
13+
[f"{name}_{value}" for name, value in zip(params_columns, x)]
14+
),
15+
axis=1,
16+
)
17+
.values.tolist()
18+
)
19+
bar = (
20+
Bar()
21+
.add_xaxis(x_data)
22+
.set_global_opts(
23+
tooltip_opts=opts.TooltipOpts(trigger="axis"),
24+
legend_opts=opts.LegendOpts(selected_mode="single"),
25+
)
26+
)
27+
for col in scores_columns:
28+
bar.add_yaxis(col, df[col].values.tolist())
29+
bar.set_series_opts(
30+
label_opts=opts.LabelOpts(is_show=False),
31+
markpoint_opts=opts.MarkPointOpts(
32+
data=[
33+
opts.MarkPointItem(type_="max", name="最大值"),
34+
opts.MarkPointItem(type_="min", name="最小值"),
35+
]
36+
),
37+
)
38+
39+
return bar

0 commit comments

Comments
 (0)