Files
deploy/pages/config/grid_strike/app.py
2024-12-02 21:35:48 +08:00

149 lines
5.4 KiB
Python

import plotly.graph_objects as go
import streamlit as st
from hummingbot.core.data_type.common import TradeType
from plotly.subplots import make_subplots
from frontend.components.config_loader import get_default_config_loader
from frontend.components.save_config import render_save_config
from frontend.pages.config.grid_strike.user_inputs import user_inputs
from frontend.pages.config.utils import get_candles
from frontend.st_utils import get_backend_api_client, initialize_st_page
from frontend.visualization import theme
from frontend.visualization.candles import get_candlestick_trace
from frontend.visualization.utils import add_traces_to_fig
def get_grid_range_traces(grid_ranges):
"""Generate horizontal line traces for grid ranges with different colors."""
dash_styles = ['solid', 'dash', 'dot', 'dashdot', 'longdash'] # 5 different styles
traces = []
buy_count = 0
sell_count = 0
for i, grid_range in enumerate(grid_ranges):
# Set color based on trade type
if grid_range["side"] == TradeType.BUY:
color = 'rgba(0, 255, 0, 1)' # Bright green for buy
dash_style = dash_styles[buy_count % len(dash_styles)]
buy_count += 1
else:
color = 'rgba(255, 0, 0, 1)' # Bright red for sell
dash_style = dash_styles[sell_count % len(dash_styles)]
sell_count += 1
# Start price line
traces.append(go.Scatter(
x=[], # Will be set to full range when plotting
y=[float(grid_range["start_price"]), float(grid_range["start_price"])],
mode='lines',
line=dict(color=color, width=1.5, dash=dash_style),
name=f'Range {i} Start: {float(grid_range["start_price"]):,.2f} ({grid_range["side"].name})',
hoverinfo='name'
))
# End price line
traces.append(go.Scatter(
x=[], # Will be set to full range when plotting
y=[float(grid_range["end_price"]), float(grid_range["end_price"])],
mode='lines',
line=dict(color=color, width=1.5, dash=dash_style),
name=f'Range {i} End: {float(grid_range["end_price"]):,.2f} ({grid_range["side"].name})',
hoverinfo='name'
))
return traces
# Initialize the Streamlit page
initialize_st_page(title="Grid Strike", icon="📊", initial_sidebar_state="expanded")
backend_api_client = get_backend_api_client()
get_default_config_loader("grid_strike")
# User inputs
inputs = user_inputs()
st.session_state["default_config"].update(inputs)
# Load candle data
candles = get_candles(
connector_name=inputs["connector_name"],
trading_pair=inputs["trading_pair"],
interval=inputs["interval"],
days=inputs["days_to_visualize"]
)
# Create a subplot with just 1 row for price action
fig = make_subplots(
rows=1, cols=1,
subplot_titles=(f'Grid Strike - {inputs["trading_pair"]} ({inputs["interval"]})',),
)
# Add basic candlestick chart
candlestick_trace = get_candlestick_trace(candles)
add_traces_to_fig(fig, [candlestick_trace], row=1, col=1)
# Add grid range visualization
grid_traces = get_grid_range_traces(inputs["grid_ranges"])
for trace in grid_traces:
# Set the x-axis range for all grid traces
trace.x = [candles.index[0], candles.index[-1]]
fig.add_trace(trace, row=1, col=1)
# Update y-axis to make sure all grid ranges and candles are visible
all_prices = []
# Add candle prices
all_prices.extend(candles['high'].tolist())
all_prices.extend(candles['low'].tolist())
# Add grid range prices
for grid_range in inputs["grid_ranges"]:
all_prices.extend([float(grid_range["start_price"]), float(grid_range["end_price"])])
y_min, y_max = min(all_prices), max(all_prices)
padding = (y_max - y_min) * 0.1 # Add 10% padding
fig.update_yaxes(range=[y_min - padding, y_max + padding])
# Update layout for better visualization
layout_updates = {
"legend": dict(
yanchor="top",
y=0.99,
xanchor="left",
x=0.01,
bgcolor="rgba(0,0,0,0.5)"
),
"hovermode": 'x unified',
"showlegend": True,
"height": 600, # Make the chart taller
"yaxis": dict(
fixedrange=False, # Allow y-axis zooming
autorange=True, # Enable auto-ranging
)
}
# Merge the default theme with our updates
fig.update_layout(
**(theme.get_default_layout() | layout_updates)
)
# Use Streamlit's functionality to display the plot
st.plotly_chart(fig, use_container_width=True)
# Add after user inputs and before saving
def prepare_config_for_save(config):
"""Prepare config for JSON serialization."""
prepared_config = config.copy()
grid_ranges = []
for grid_range in prepared_config["grid_ranges"]:
grid_range = grid_range.copy()
grid_range["side"] = grid_range["side"].value
grid_range["open_order_type"] = grid_range["open_order_type"].value
grid_range["take_profit_order_type"] = grid_range["take_profit_order_type"].value
grid_ranges.append(grid_range)
prepared_config["grid_ranges"] = grid_ranges
prepared_config["position_mode"] = prepared_config["position_mode"].value
del prepared_config["candles_connector"]
del prepared_config["interval"]
del prepared_config["days_to_visualize"]
return prepared_config
# Replace the render_save_config line with:
render_save_config(st.session_state["default_config"]["id"],
prepare_config_for_save(st.session_state["default_config"]))