mirror of
https://github.com/aljazceru/hummingbot-dashboard.git
synced 2025-12-23 08:14:23 +01:00
187 lines
8.3 KiB
Python
187 lines
8.3 KiB
Python
import datetime
|
|
import threading
|
|
import webbrowser
|
|
|
|
import streamlit as st
|
|
from pathlib import Path
|
|
from streamlit_ace import st_ace
|
|
|
|
import constants
|
|
from quants_lab.strategy.strategy_analysis import StrategyAnalysis
|
|
from utils import os_utils
|
|
from utils.file_templates import strategy_optimization_template, directional_strategy_template
|
|
from utils.os_utils import load_directional_strategies, save_file, get_function_from_file
|
|
import optuna
|
|
|
|
# Page metadata
|
|
title = "Backtest Manager"
|
|
icon = "⚙️"
|
|
|
|
st.set_page_config(
|
|
page_title=title,
|
|
page_icon=icon,
|
|
layout="wide",
|
|
)
|
|
st.title(f"{icon} {title}")
|
|
|
|
# About this page
|
|
current_directory = Path(__file__).parent
|
|
readme_path = current_directory / "README.md"
|
|
with st.expander("About This Page"):
|
|
st.write(readme_path.read_text())
|
|
|
|
# Start content here
|
|
if "strategy_params" not in st.session_state:
|
|
st.session_state.strategy_params = {}
|
|
|
|
create, modify, backtest, optimize, analyze = st.tabs(["Create", "Modify", "Backtest", "Optimize", "Analyze"])
|
|
|
|
with create:
|
|
# TODO:
|
|
# * Add videos explaining how to the triple barrier method works and how the backtesting is designed,
|
|
# link to video of how to create a strategy, etc in a toggle.
|
|
# * Add functionality to start strategy creation from scratch or by duplicating an existing one
|
|
c1, c2 = st.columns([4, 1])
|
|
with c1:
|
|
# TODO: Allow change the strategy name and see the effect in the code
|
|
strategy_name = st.text_input("Strategy class name", value="CustomStrategy")
|
|
with c2:
|
|
update_strategy_name = st.button("Update Strategy Name")
|
|
|
|
c1, c2 = st.columns([4, 1])
|
|
with c1:
|
|
# TODO: every time that we save and run the optimizations, we should save the code in a file
|
|
# so the user then can correlate the results with the code.
|
|
if update_strategy_name:
|
|
st.session_state.directional_strategy_code = st_ace(key="create_directional_strategy",
|
|
value=directional_strategy_template(strategy_name),
|
|
language='python',
|
|
keybinding='vscode',
|
|
theme='pastel_on_dark')
|
|
with c2:
|
|
if st.button("Save strategy"):
|
|
save_file(name=f"{strategy_name.lower()}.py", content=st.session_state.directional_strategy_code,
|
|
path=constants.DIRECTIONAL_STRATEGIES_PATH)
|
|
st.success(f"Strategy {strategy_name} saved successfully")
|
|
|
|
with modify:
|
|
pass
|
|
|
|
with backtest:
|
|
# TODO:
|
|
# * Add videos explaining how to the triple barrier method works and how the backtesting is designed,
|
|
# link to video of how to create a strategy, etc in a toggle.
|
|
# * Add performance analysis graphs of the backtesting run
|
|
strategies = load_directional_strategies(constants.DIRECTIONAL_STRATEGIES_PATH)
|
|
strategy_to_optimize = st.selectbox("Select strategy to backtest", strategies.keys())
|
|
strategy = strategies[strategy_to_optimize]
|
|
strategy_config = strategy["config"]
|
|
field_schema = strategy_config.schema()["properties"]
|
|
st.write("## Strategy parameters")
|
|
c1, c2 = st.columns([5, 1])
|
|
with c1:
|
|
columns = st.columns(4)
|
|
column_index = 0
|
|
for field_name, properties in field_schema.items():
|
|
field_type = properties["type"]
|
|
with columns[column_index]:
|
|
if field_type in ["number", "integer"]:
|
|
field_value = st.number_input(field_name,
|
|
value=properties["default"],
|
|
min_value=properties.get("minimum"),
|
|
max_value=properties.get("maximum"),
|
|
key=field_name)
|
|
elif field_type == "string":
|
|
field_value = st.text_input(field_name, value=properties["default"])
|
|
elif field_type == "boolean":
|
|
# TODO: Add support for boolean fields in optimize tab
|
|
field_value = st.checkbox(field_name, value=properties["default"])
|
|
else:
|
|
raise ValueError(f"Field type {field_type} not supported")
|
|
st.session_state["strategy_params"][field_name] = field_value
|
|
column_index = (column_index + 1) % 4
|
|
with c2:
|
|
add_positions = st.checkbox("Add positions", value=True)
|
|
add_volume = st.checkbox("Add volume", value=True)
|
|
add_pnl = st.checkbox("Add PnL", value=True)
|
|
|
|
run_backtesting_button = st.button("Run Backtesting!")
|
|
if run_backtesting_button:
|
|
config = strategy["config"](**st.session_state["strategy_params"])
|
|
strategy = strategy["class"](config=config)
|
|
# TODO: add form for order amount, leverage, tp, sl, etc.
|
|
|
|
market_data, positions = strategy.run_backtesting(
|
|
start='2021-04-01',
|
|
order_amount=50,
|
|
leverage=20,
|
|
initial_portfolio=100,
|
|
take_profit_multiplier=2.3,
|
|
stop_loss_multiplier=1.2,
|
|
time_limit=60 * 60 * 3,
|
|
std_span=None,
|
|
)
|
|
strategy_analysis = StrategyAnalysis(
|
|
positions=positions,
|
|
candles_df=market_data,
|
|
)
|
|
st.text(strategy_analysis.text_report())
|
|
# TODO: check why the pnl is not being plotted
|
|
strategy_analysis.create_base_figure(volume=add_volume, positions=add_positions, trade_pnl=add_pnl)
|
|
st.plotly_chart(strategy_analysis.figure(), use_container_width=True)
|
|
|
|
with optimize:
|
|
# TODO:
|
|
# * Add videos explaining how to use the optimization tool, quick intro to optuna, etc in a toggle
|
|
with st.container():
|
|
c1, c2, c3 = st.columns([1, 1, 1])
|
|
with c1:
|
|
strategies = load_directional_strategies(constants.DIRECTIONAL_STRATEGIES_PATH)
|
|
strategy_to_optimize = st.selectbox("Select strategy to optimize", strategies.keys())
|
|
with c2:
|
|
today = datetime.datetime.today()
|
|
# TODO: add hints about the study name
|
|
STUDY_NAME = st.text_input("Study name",
|
|
f"{strategy_to_optimize}_study_{today.day:02d}-{today.month:02d}-{today.year}")
|
|
with c3:
|
|
generate_optimization_code_button = st.button("Generate Optimization Code")
|
|
if st.button("Launch optuna dashboard"):
|
|
os_utils.execute_bash_command(f"optuna-dashboard sqlite:///data/backtesting/backtesting_report.db")
|
|
webbrowser.open("http://127.0.0.1:8080/dashboard", new=2)
|
|
|
|
c1, c2 = st.columns([4, 1])
|
|
if generate_optimization_code_button:
|
|
with c1:
|
|
# TODO: every time that we save and run the optimizations, we should save the code in a file
|
|
# so the user then can correlate the results with the code.
|
|
st.session_state.optimization_code = st_ace(key="create_optimization_code",
|
|
value=strategy_optimization_template(
|
|
strategy_info=strategies[strategy_to_optimize]),
|
|
language='python',
|
|
keybinding='vscode',
|
|
theme='pastel_on_dark')
|
|
if "optimization_code" in st.session_state:
|
|
with c2:
|
|
if st.button("Run optimization"):
|
|
save_file(name=f"{STUDY_NAME}.py", content=st.session_state.optimization_code, path=constants.OPTIMIZATIONS_PATH)
|
|
study = optuna.create_study(direction="maximize", study_name=STUDY_NAME,
|
|
storage="sqlite:///data/backtesting/backtesting_report.db",
|
|
load_if_exists=True)
|
|
objective = get_function_from_file(file_path=f"{constants.OPTIMIZATIONS_PATH}/{STUDY_NAME}.py",
|
|
function_name="objective")
|
|
|
|
|
|
def optimization_process():
|
|
study.optimize(objective, n_trials=2000)
|
|
|
|
|
|
optimization_thread = threading.Thread(target=optimization_process)
|
|
optimization_thread.start()
|
|
|
|
|
|
with analyze:
|
|
# TODO:
|
|
# * Add graphs for all backtesting results
|
|
# * Add management of backtesting results (delete, rename, save, share, upload s3, etc)
|
|
pass
|