better charts
This commit is contained in:
parent
cb3ec0602c
commit
fff5e8cfb7
@ -55,4 +55,6 @@ python test_model.py
|
|||||||
|
|
||||||
python train_with_realtime_ticks.py
|
python train_with_realtime_ticks.py
|
||||||
python NN/train_rl.py
|
python NN/train_rl.py
|
||||||
python train_rl_with_realtime.py
|
python train_rl_with_realtime.py
|
||||||
|
|
||||||
|
python train_rl_with_realtime.py --episodes 2 --no-train --visualize-only
|
464
realtime.py
464
realtime.py
@ -1,7 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import datetime
|
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
import websockets
|
import websockets
|
||||||
import plotly.graph_objects as go
|
import plotly.graph_objects as go
|
||||||
@ -1694,13 +1694,13 @@ class RealTimeChart:
|
|||||||
else:
|
else:
|
||||||
df_1d = self.tick_storage.get_candles(interval_seconds=86400)
|
df_1d = self.tick_storage.get_candles(interval_seconds=86400)
|
||||||
|
|
||||||
# Limit the number of candles to display
|
# Limit the number of candles to display but show more for context
|
||||||
if df_1m is not None and not df_1m.empty:
|
if df_1m is not None and not df_1m.empty:
|
||||||
df_1m = df_1m.tail(100)
|
df_1m = df_1m.tail(200) # Show more 1m candles (3+ hours)
|
||||||
if df_1h is not None and not df_1h.empty:
|
if df_1h is not None and not df_1h.empty:
|
||||||
df_1h = df_1h.tail(48) # Last 2 days
|
df_1h = df_1h.tail(72) # Show 3 days of hourly data
|
||||||
if df_1d is not None and not df_1d.empty:
|
if df_1d is not None and not df_1d.empty:
|
||||||
df_1d = df_1d.tail(30) # Last month
|
df_1d = df_1d.tail(60) # Show 2 months of daily data
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error getting additional timeframes: {str(e)}")
|
logger.error(f"Error getting additional timeframes: {str(e)}")
|
||||||
@ -1757,6 +1757,155 @@ class RealTimeChart:
|
|||||||
),
|
),
|
||||||
row=2, col=1
|
row=2, col=1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add buy/sell markers and PnL annotations to the main chart
|
||||||
|
if hasattr(self, 'trades') and self.trades:
|
||||||
|
buy_times = []
|
||||||
|
buy_prices = []
|
||||||
|
buy_markers = []
|
||||||
|
sell_times = []
|
||||||
|
sell_prices = []
|
||||||
|
sell_markers = []
|
||||||
|
|
||||||
|
# Filter trades to only include recent ones (last 100)
|
||||||
|
recent_trades = self.trades[-100:]
|
||||||
|
|
||||||
|
for trade in recent_trades:
|
||||||
|
# Convert timestamp to datetime if it's not already
|
||||||
|
trade_time = trade.get('timestamp')
|
||||||
|
if isinstance(trade_time, (int, float)):
|
||||||
|
trade_time = pd.to_datetime(trade_time, unit='ms')
|
||||||
|
|
||||||
|
price = trade.get('price', 0)
|
||||||
|
pnl = trade.get('pnl', None)
|
||||||
|
action = trade.get('action', 'SELL') # Default to SELL
|
||||||
|
|
||||||
|
if action == 'BUY':
|
||||||
|
buy_times.append(trade_time)
|
||||||
|
buy_prices.append(price)
|
||||||
|
buy_markers.append("")
|
||||||
|
elif action == 'SELL':
|
||||||
|
sell_times.append(trade_time)
|
||||||
|
sell_prices.append(price)
|
||||||
|
# Add PnL as marker text if available
|
||||||
|
if pnl is not None:
|
||||||
|
pnl_text = f"{pnl:.4f}" if abs(pnl) < 0.01 else f"{pnl:.2f}"
|
||||||
|
sell_markers.append(pnl_text)
|
||||||
|
else:
|
||||||
|
sell_markers.append("")
|
||||||
|
|
||||||
|
# Add buy markers
|
||||||
|
if buy_times:
|
||||||
|
fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=buy_times,
|
||||||
|
y=buy_prices,
|
||||||
|
mode='markers',
|
||||||
|
name='Buy',
|
||||||
|
marker=dict(
|
||||||
|
symbol='triangle-up',
|
||||||
|
size=12,
|
||||||
|
color='rgba(0,255,0,0.8)',
|
||||||
|
line=dict(width=1, color='darkgreen')
|
||||||
|
),
|
||||||
|
text=buy_markers,
|
||||||
|
hoverinfo='x+y+text'
|
||||||
|
),
|
||||||
|
row=1, col=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add vertical and horizontal connecting lines for buys
|
||||||
|
for i, (btime, bprice) in enumerate(zip(buy_times, buy_prices)):
|
||||||
|
# Add vertical dashed line to time axis
|
||||||
|
fig.add_shape(
|
||||||
|
type="line",
|
||||||
|
x0=btime, x1=btime,
|
||||||
|
y0=y_min, y1=bprice,
|
||||||
|
line=dict(color="rgba(0,255,0,0.5)", width=1, dash="dash"),
|
||||||
|
row=1, col=1
|
||||||
|
)
|
||||||
|
# Add horizontal dashed line showing the price level
|
||||||
|
fig.add_shape(
|
||||||
|
type="line",
|
||||||
|
x0=df.index.min(), x1=btime,
|
||||||
|
y0=bprice, y1=bprice,
|
||||||
|
line=dict(color="rgba(0,255,0,0.5)", width=1, dash="dash"),
|
||||||
|
row=1, col=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add sell markers with PnL annotations
|
||||||
|
if sell_times:
|
||||||
|
fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=sell_times,
|
||||||
|
y=sell_prices,
|
||||||
|
mode='markers+text',
|
||||||
|
name='Sell',
|
||||||
|
marker=dict(
|
||||||
|
symbol='triangle-down',
|
||||||
|
size=12,
|
||||||
|
color='rgba(255,0,0,0.8)',
|
||||||
|
line=dict(width=1, color='darkred')
|
||||||
|
),
|
||||||
|
text=sell_markers,
|
||||||
|
textposition='top center',
|
||||||
|
textfont=dict(size=10),
|
||||||
|
hoverinfo='x+y+text'
|
||||||
|
),
|
||||||
|
row=1, col=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add vertical and horizontal connecting lines for sells
|
||||||
|
for i, (stime, sprice) in enumerate(zip(sell_times, sell_prices)):
|
||||||
|
# Add vertical dashed line to time axis
|
||||||
|
fig.add_shape(
|
||||||
|
type="line",
|
||||||
|
x0=stime, x1=stime,
|
||||||
|
y0=y_min, y1=sprice,
|
||||||
|
line=dict(color="rgba(255,0,0,0.5)", width=1, dash="dash"),
|
||||||
|
row=1, col=1
|
||||||
|
)
|
||||||
|
# Add horizontal dashed line showing the price level
|
||||||
|
fig.add_shape(
|
||||||
|
type="line",
|
||||||
|
x0=df.index.min(), x1=stime,
|
||||||
|
y0=sprice, y1=sprice,
|
||||||
|
line=dict(color="rgba(255,0,0,0.5)", width=1, dash="dash"),
|
||||||
|
row=1, col=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add connecting lines between consecutive buy-sell pairs
|
||||||
|
if len(buy_times) > 0 and len(sell_times) > 0:
|
||||||
|
# Create pairs of buy-sell trades based on timestamps
|
||||||
|
pairs = []
|
||||||
|
buys_copy = list(zip(buy_times, buy_prices))
|
||||||
|
|
||||||
|
for i, (stime, sprice) in enumerate(zip(sell_times, sell_prices)):
|
||||||
|
# Find the most recent buy before this sell
|
||||||
|
matching_buy = None
|
||||||
|
for j, (btime, bprice) in enumerate(buys_copy):
|
||||||
|
if btime < stime:
|
||||||
|
matching_buy = (btime, bprice)
|
||||||
|
buys_copy.pop(j) # Remove this buy to prevent reuse
|
||||||
|
break
|
||||||
|
|
||||||
|
if matching_buy:
|
||||||
|
pairs.append((matching_buy, (stime, sprice)))
|
||||||
|
|
||||||
|
# Add connecting lines for each pair
|
||||||
|
for (btime, bprice), (stime, sprice) in pairs:
|
||||||
|
# Draw line connecting the buy and sell points
|
||||||
|
fig.add_shape(
|
||||||
|
type="line",
|
||||||
|
x0=btime, x1=stime,
|
||||||
|
y0=bprice, y1=sprice,
|
||||||
|
line=dict(
|
||||||
|
color="rgba(255,255,255,0.5)",
|
||||||
|
width=1,
|
||||||
|
dash="dot"
|
||||||
|
),
|
||||||
|
row=1, col=1
|
||||||
|
)
|
||||||
|
|
||||||
# Add 1m chart
|
# Add 1m chart
|
||||||
if df_1m is not None and not df_1m.empty and 'open' in df_1m.columns:
|
if df_1m is not None and not df_1m.empty and 'open' in df_1m.columns:
|
||||||
@ -1772,7 +1921,100 @@ class RealTimeChart:
|
|||||||
),
|
),
|
||||||
row=3, col=1
|
row=3, col=1
|
||||||
)
|
)
|
||||||
fig.update_xaxes(title_text="", row=3, col=1)
|
|
||||||
|
# Set appropriate date format for 1m chart
|
||||||
|
fig.update_xaxes(
|
||||||
|
title_text="",
|
||||||
|
row=3,
|
||||||
|
col=1,
|
||||||
|
tickformat="%H:%M",
|
||||||
|
tickmode="auto",
|
||||||
|
nticks=12
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add buy/sell markers to 1m chart if they fall within the visible timeframe
|
||||||
|
if hasattr(self, 'trades') and self.trades:
|
||||||
|
# Filter trades visible in 1m timeframe
|
||||||
|
min_time = df_1m.index.min()
|
||||||
|
max_time = df_1m.index.max()
|
||||||
|
|
||||||
|
# Ensure min_time and max_time are pandas.Timestamp objects
|
||||||
|
if isinstance(min_time, (int, float)):
|
||||||
|
min_time = pd.to_datetime(min_time, unit='ms')
|
||||||
|
if isinstance(max_time, (int, float)):
|
||||||
|
max_time = pd.to_datetime(max_time, unit='ms')
|
||||||
|
|
||||||
|
# Collect only trades within this timeframe
|
||||||
|
minute_buy_times = []
|
||||||
|
minute_buy_prices = []
|
||||||
|
minute_sell_times = []
|
||||||
|
minute_sell_prices = []
|
||||||
|
|
||||||
|
for trade in self.trades[-100:]:
|
||||||
|
trade_time = trade.get('timestamp')
|
||||||
|
if isinstance(trade_time, (int, float)):
|
||||||
|
# Convert numeric timestamp to datetime
|
||||||
|
trade_time = pd.to_datetime(trade_time, unit='ms')
|
||||||
|
elif not isinstance(trade_time, pd.Timestamp) and not isinstance(trade_time, datetime):
|
||||||
|
# Skip trades with invalid timestamp format
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if trade falls within 1m chart timeframe
|
||||||
|
try:
|
||||||
|
if min_time <= trade_time <= max_time:
|
||||||
|
price = trade.get('price', 0)
|
||||||
|
action = trade.get('action', 'SELL')
|
||||||
|
|
||||||
|
if action == 'BUY':
|
||||||
|
minute_buy_times.append(trade_time)
|
||||||
|
minute_buy_prices.append(price)
|
||||||
|
elif action == 'SELL':
|
||||||
|
minute_sell_times.append(trade_time)
|
||||||
|
minute_sell_prices.append(price)
|
||||||
|
except TypeError:
|
||||||
|
# If comparison fails due to type mismatch, log the error and skip this trade
|
||||||
|
logger.warning(f"Type mismatch in timestamp comparison: min_time={type(min_time)}, trade_time={type(trade_time)}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Add buy markers to 1m chart
|
||||||
|
if minute_buy_times:
|
||||||
|
fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=minute_buy_times,
|
||||||
|
y=minute_buy_prices,
|
||||||
|
mode='markers',
|
||||||
|
name='Buy (1m)',
|
||||||
|
marker=dict(
|
||||||
|
symbol='triangle-up',
|
||||||
|
size=8,
|
||||||
|
color='rgba(0,255,0,0.8)',
|
||||||
|
line=dict(width=1, color='darkgreen')
|
||||||
|
),
|
||||||
|
showlegend=False,
|
||||||
|
hoverinfo='x+y'
|
||||||
|
),
|
||||||
|
row=3, col=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add sell markers to 1m chart
|
||||||
|
if minute_sell_times:
|
||||||
|
fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=minute_sell_times,
|
||||||
|
y=minute_sell_prices,
|
||||||
|
mode='markers',
|
||||||
|
name='Sell (1m)',
|
||||||
|
marker=dict(
|
||||||
|
symbol='triangle-down',
|
||||||
|
size=8,
|
||||||
|
color='rgba(255,0,0,0.8)',
|
||||||
|
line=dict(width=1, color='darkred')
|
||||||
|
),
|
||||||
|
showlegend=False,
|
||||||
|
hoverinfo='x+y'
|
||||||
|
),
|
||||||
|
row=3, col=1
|
||||||
|
)
|
||||||
|
|
||||||
# Add 1h chart
|
# Add 1h chart
|
||||||
if df_1h is not None and not df_1h.empty and 'open' in df_1h.columns:
|
if df_1h is not None and not df_1h.empty and 'open' in df_1h.columns:
|
||||||
@ -1788,8 +2030,100 @@ class RealTimeChart:
|
|||||||
),
|
),
|
||||||
row=4, col=1
|
row=4, col=1
|
||||||
)
|
)
|
||||||
fig.update_xaxes(title_text="", row=4, col=1)
|
|
||||||
|
|
||||||
|
# Set appropriate date format for 1h chart
|
||||||
|
fig.update_xaxes(
|
||||||
|
title_text="",
|
||||||
|
row=4,
|
||||||
|
col=1,
|
||||||
|
tickformat="%m-%d %H:%M",
|
||||||
|
tickmode="auto",
|
||||||
|
nticks=8
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add buy/sell markers to 1h chart if they fall within the visible timeframe
|
||||||
|
if hasattr(self, 'trades') and self.trades:
|
||||||
|
# Filter trades visible in 1h timeframe
|
||||||
|
min_time = df_1h.index.min()
|
||||||
|
max_time = df_1h.index.max()
|
||||||
|
|
||||||
|
# Ensure min_time and max_time are pandas.Timestamp objects
|
||||||
|
if isinstance(min_time, (int, float)):
|
||||||
|
min_time = pd.to_datetime(min_time, unit='ms')
|
||||||
|
if isinstance(max_time, (int, float)):
|
||||||
|
max_time = pd.to_datetime(max_time, unit='ms')
|
||||||
|
|
||||||
|
# Collect only trades within this timeframe
|
||||||
|
hour_buy_times = []
|
||||||
|
hour_buy_prices = []
|
||||||
|
hour_sell_times = []
|
||||||
|
hour_sell_prices = []
|
||||||
|
|
||||||
|
for trade in self.trades[-200:]: # Check more trades for longer timeframe
|
||||||
|
trade_time = trade.get('timestamp')
|
||||||
|
if isinstance(trade_time, (int, float)):
|
||||||
|
# Convert numeric timestamp to datetime
|
||||||
|
trade_time = pd.to_datetime(trade_time, unit='ms')
|
||||||
|
elif not isinstance(trade_time, pd.Timestamp) and not isinstance(trade_time, datetime):
|
||||||
|
# Skip trades with invalid timestamp format
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if trade falls within 1h chart timeframe
|
||||||
|
try:
|
||||||
|
if min_time <= trade_time <= max_time:
|
||||||
|
price = trade.get('price', 0)
|
||||||
|
action = trade.get('action', 'SELL')
|
||||||
|
|
||||||
|
if action == 'BUY':
|
||||||
|
hour_buy_times.append(trade_time)
|
||||||
|
hour_buy_prices.append(price)
|
||||||
|
elif action == 'SELL':
|
||||||
|
hour_sell_times.append(trade_time)
|
||||||
|
hour_sell_prices.append(price)
|
||||||
|
except TypeError:
|
||||||
|
# If comparison fails due to type mismatch, log the error and skip this trade
|
||||||
|
logger.warning(f"Type mismatch in timestamp comparison: min_time={type(min_time)}, trade_time={type(trade_time)}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Add buy markers to 1h chart
|
||||||
|
if hour_buy_times:
|
||||||
|
fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=hour_buy_times,
|
||||||
|
y=hour_buy_prices,
|
||||||
|
mode='markers',
|
||||||
|
name='Buy (1h)',
|
||||||
|
marker=dict(
|
||||||
|
symbol='triangle-up',
|
||||||
|
size=6,
|
||||||
|
color='rgba(0,255,0,0.8)',
|
||||||
|
line=dict(width=1, color='darkgreen')
|
||||||
|
),
|
||||||
|
showlegend=False,
|
||||||
|
hoverinfo='x+y'
|
||||||
|
),
|
||||||
|
row=4, col=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add sell markers to 1h chart
|
||||||
|
if hour_sell_times:
|
||||||
|
fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=hour_sell_times,
|
||||||
|
y=hour_sell_prices,
|
||||||
|
mode='markers',
|
||||||
|
name='Sell (1h)',
|
||||||
|
marker=dict(
|
||||||
|
symbol='triangle-down',
|
||||||
|
size=6,
|
||||||
|
color='rgba(255,0,0,0.8)',
|
||||||
|
line=dict(width=1, color='darkred')
|
||||||
|
),
|
||||||
|
showlegend=False,
|
||||||
|
hoverinfo='x+y'
|
||||||
|
),
|
||||||
|
row=4, col=1
|
||||||
|
)
|
||||||
# Add 1d chart
|
# Add 1d chart
|
||||||
if df_1d is not None and not df_1d.empty and 'open' in df_1d.columns:
|
if df_1d is not None and not df_1d.empty and 'open' in df_1d.columns:
|
||||||
fig.add_trace(
|
fig.add_trace(
|
||||||
@ -1804,7 +2138,100 @@ class RealTimeChart:
|
|||||||
),
|
),
|
||||||
row=5, col=1
|
row=5, col=1
|
||||||
)
|
)
|
||||||
fig.update_xaxes(title_text="", row=5, col=1)
|
|
||||||
|
# Set appropriate date format for 1d chart
|
||||||
|
fig.update_xaxes(
|
||||||
|
title_text="",
|
||||||
|
row=5,
|
||||||
|
col=1,
|
||||||
|
tickformat="%Y-%m-%d",
|
||||||
|
tickmode="auto",
|
||||||
|
nticks=10
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add buy/sell markers to 1d chart if they fall within the visible timeframe
|
||||||
|
if hasattr(self, 'trades') and self.trades:
|
||||||
|
# Filter trades visible in 1d timeframe
|
||||||
|
min_time = df_1d.index.min()
|
||||||
|
max_time = df_1d.index.max()
|
||||||
|
|
||||||
|
# Ensure min_time and max_time are pandas.Timestamp objects
|
||||||
|
if isinstance(min_time, (int, float)):
|
||||||
|
min_time = pd.to_datetime(min_time, unit='ms')
|
||||||
|
if isinstance(max_time, (int, float)):
|
||||||
|
max_time = pd.to_datetime(max_time, unit='ms')
|
||||||
|
|
||||||
|
# Collect only trades within this timeframe
|
||||||
|
day_buy_times = []
|
||||||
|
day_buy_prices = []
|
||||||
|
day_sell_times = []
|
||||||
|
day_sell_prices = []
|
||||||
|
|
||||||
|
for trade in self.trades[-300:]: # Check more trades for daily timeframe
|
||||||
|
trade_time = trade.get('timestamp')
|
||||||
|
if isinstance(trade_time, (int, float)):
|
||||||
|
# Convert numeric timestamp to datetime
|
||||||
|
trade_time = pd.to_datetime(trade_time, unit='ms')
|
||||||
|
elif not isinstance(trade_time, pd.Timestamp) and not isinstance(trade_time, datetime):
|
||||||
|
# Skip trades with invalid timestamp format
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if trade falls within 1d chart timeframe
|
||||||
|
try:
|
||||||
|
if min_time <= trade_time <= max_time:
|
||||||
|
price = trade.get('price', 0)
|
||||||
|
action = trade.get('action', 'SELL')
|
||||||
|
|
||||||
|
if action == 'BUY':
|
||||||
|
day_buy_times.append(trade_time)
|
||||||
|
day_buy_prices.append(price)
|
||||||
|
elif action == 'SELL':
|
||||||
|
day_sell_times.append(trade_time)
|
||||||
|
day_sell_prices.append(price)
|
||||||
|
except TypeError:
|
||||||
|
# If comparison fails due to type mismatch, log the error and skip this trade
|
||||||
|
logger.warning(f"Type mismatch in timestamp comparison: min_time={type(min_time)}, trade_time={type(trade_time)}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Add buy markers to 1d chart
|
||||||
|
if day_buy_times:
|
||||||
|
fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=day_buy_times,
|
||||||
|
y=day_buy_prices,
|
||||||
|
mode='markers',
|
||||||
|
name='Buy (1d)',
|
||||||
|
marker=dict(
|
||||||
|
symbol='triangle-up',
|
||||||
|
size=5,
|
||||||
|
color='rgba(0,255,0,0.8)',
|
||||||
|
line=dict(width=1, color='darkgreen')
|
||||||
|
),
|
||||||
|
showlegend=False,
|
||||||
|
hoverinfo='x+y'
|
||||||
|
),
|
||||||
|
row=5, col=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add sell markers to 1d chart
|
||||||
|
if day_sell_times:
|
||||||
|
fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=day_sell_times,
|
||||||
|
y=day_sell_prices,
|
||||||
|
mode='markers',
|
||||||
|
name='Sell (1d)',
|
||||||
|
marker=dict(
|
||||||
|
symbol='triangle-down',
|
||||||
|
size=5,
|
||||||
|
color='rgba(255,0,0,0.8)',
|
||||||
|
line=dict(width=1, color='darkred')
|
||||||
|
),
|
||||||
|
showlegend=False,
|
||||||
|
hoverinfo='x+y'
|
||||||
|
),
|
||||||
|
row=5, col=1
|
||||||
|
)
|
||||||
|
|
||||||
# Add trading info annotation if available
|
# Add trading info annotation if available
|
||||||
if hasattr(self, 'current_signal') and self.current_signal:
|
if hasattr(self, 'current_signal') and self.current_signal:
|
||||||
@ -1813,12 +2240,16 @@ class RealTimeChart:
|
|||||||
# Format position value
|
# Format position value
|
||||||
position_text = f"{self.current_position:.4f}" if self.current_position < 0.01 else f"{self.current_position:.2f}"
|
position_text = f"{self.current_position:.4f}" if self.current_position < 0.01 else f"{self.current_position:.2f}"
|
||||||
|
|
||||||
|
# Format PnL with color based on value
|
||||||
|
pnl_color = "#33DD33" if self.session_pnl >= 0 else "#FF4444"
|
||||||
|
pnl_text = f"<b style='color:{pnl_color}'>{self.session_pnl:.4f}</b>"
|
||||||
|
|
||||||
# Create trading info text
|
# Create trading info text
|
||||||
info_text = (
|
info_text = (
|
||||||
f"Signal: <b style='color:{signal_color}'>{self.current_signal}</b> | "
|
f"Signal: <b style='color:{signal_color}'>{self.current_signal}</b> | "
|
||||||
f"Position: <b>{position_text}</b> | "
|
f"Position: <b>{position_text}</b> | "
|
||||||
f"Balance: <b>${self.session_balance:.2f}</b> | "
|
f"Balance: <b>${self.session_balance:.2f}</b> | "
|
||||||
f"PnL: <b>{self.session_pnl:.4f}</b>"
|
f"PnL: {pnl_text}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add annotation
|
# Add annotation
|
||||||
@ -1858,10 +2289,22 @@ class RealTimeChart:
|
|||||||
xaxis5_rangeslider_visible=False
|
xaxis5_rangeslider_visible=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Improve date formatting for the main chart
|
||||||
|
fig.update_xaxes(
|
||||||
|
title_text="",
|
||||||
|
row=1,
|
||||||
|
col=1,
|
||||||
|
tickformat="%H:%M:%S",
|
||||||
|
tickmode="auto",
|
||||||
|
nticks=15
|
||||||
|
)
|
||||||
|
|
||||||
return fig
|
return fig
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error updating chart: {str(e)}")
|
logger.error(f"Error updating chart: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
fig = go.Figure()
|
fig = go.Figure()
|
||||||
fig.add_annotation(
|
fig.add_annotation(
|
||||||
x=0.5, y=0.5,
|
x=0.5, y=0.5,
|
||||||
@ -1958,6 +2401,7 @@ class RealTimeChart:
|
|||||||
tick_count += 1
|
tick_count += 1
|
||||||
|
|
||||||
# Also update the old candlestick data for backward compatibility
|
# Also update the old candlestick data for backward compatibility
|
||||||
|
# Add check to ensure the candlestick_data attribute exists before using it
|
||||||
if hasattr(self, 'candlestick_data'):
|
if hasattr(self, 'candlestick_data'):
|
||||||
self.candlestick_data.update_from_trade(trade_data)
|
self.candlestick_data.update_from_trade(trade_data)
|
||||||
|
|
||||||
@ -2403,4 +2847,4 @@ if __name__ == "__main__":
|
|||||||
try:
|
try:
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
logger.info("Application terminated by user")
|
logger.info("Application terminated by user")
|
||||||
|
@ -534,7 +534,7 @@ def run_training_thread(chart):
|
|||||||
def training_thread_func():
|
def training_thread_func():
|
||||||
try:
|
try:
|
||||||
# Use a small number of episodes to test termination handling
|
# Use a small number of episodes to test termination handling
|
||||||
integrator.start_training(num_episodes=2, max_steps=500)
|
integrator.start_training(num_episodes=100, max_steps=2000)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error in training thread: {str(e)}")
|
logger.error(f"Error in training thread: {str(e)}")
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user