fix Pnl, cob
This commit is contained in:
@ -239,9 +239,28 @@ class CleanTradingDashboard:
|
||||
current_price = self._get_current_price('ETH/USDT')
|
||||
price_str = f"${current_price:.2f}" if current_price else "Loading..."
|
||||
|
||||
# Calculate session P&L
|
||||
session_pnl_str = f"${self.session_pnl:.2f}"
|
||||
session_pnl_class = "text-success" if self.session_pnl >= 0 else "text-danger"
|
||||
# Calculate session P&L including unrealized P&L from current position
|
||||
total_session_pnl = self.session_pnl # Start with realized P&L
|
||||
|
||||
# Add unrealized P&L from current position (x50 leverage)
|
||||
if self.current_position and current_price:
|
||||
side = self.current_position.get('side', 'UNKNOWN')
|
||||
size = self.current_position.get('size', 0)
|
||||
entry_price = self.current_position.get('price', 0)
|
||||
|
||||
if entry_price and size > 0:
|
||||
# Calculate unrealized P&L with x50 leverage
|
||||
if side.upper() == 'LONG' or side.upper() == 'BUY':
|
||||
raw_pnl_per_unit = current_price - entry_price
|
||||
else: # SHORT or SELL
|
||||
raw_pnl_per_unit = entry_price - current_price
|
||||
|
||||
# Apply x50 leverage to unrealized P&L
|
||||
leveraged_unrealized_pnl = raw_pnl_per_unit * size * 50
|
||||
total_session_pnl += leveraged_unrealized_pnl
|
||||
|
||||
session_pnl_str = f"${total_session_pnl:.2f}"
|
||||
session_pnl_class = "text-success" if total_session_pnl >= 0 else "text-danger"
|
||||
|
||||
# Current position with unrealized P&L (x50 leverage)
|
||||
position_str = "No Position"
|
||||
@ -620,18 +639,18 @@ class CleanTradingDashboard:
|
||||
"""Add model predictions to the chart - ONLY EXECUTED TRADES on main chart"""
|
||||
try:
|
||||
# Only show EXECUTED TRADES on the main 1m chart
|
||||
executed_signals = [signal for signal in self.recent_decisions if signal.get('executed', False)]
|
||||
executed_signals = [signal for signal in self.recent_decisions if self._get_signal_attribute(signal, 'executed', False)]
|
||||
|
||||
if executed_signals:
|
||||
# Separate by prediction type
|
||||
# Separate by prediction type
|
||||
buy_trades = []
|
||||
sell_trades = []
|
||||
|
||||
for signal in executed_signals[-20:]: # Last 20 executed trades
|
||||
signal_time = signal.get('timestamp')
|
||||
signal_price = signal.get('price', 0)
|
||||
signal_action = signal.get('action', 'HOLD')
|
||||
signal_confidence = signal.get('confidence', 0)
|
||||
signal_time = self._get_signal_attribute(signal, 'timestamp')
|
||||
signal_price = self._get_signal_attribute(signal, 'price', 0)
|
||||
signal_action = self._get_signal_attribute(signal, 'action', 'HOLD')
|
||||
signal_confidence = self._get_signal_attribute(signal, 'confidence', 0)
|
||||
|
||||
if signal_time and signal_price and signal_confidence > 0:
|
||||
# Convert timestamp if needed
|
||||
@ -657,51 +676,51 @@ class CleanTradingDashboard:
|
||||
|
||||
# Add EXECUTED BUY trades (large green circles)
|
||||
if buy_trades:
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=[t['x'] for t in buy_trades],
|
||||
y=[t['y'] for t in buy_trades],
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
symbol='circle',
|
||||
size=15,
|
||||
color='rgba(0, 255, 100, 0.9)',
|
||||
line=dict(width=3, color='green')
|
||||
),
|
||||
name='EXECUTED BUY',
|
||||
showlegend=True,
|
||||
showlegend=True,
|
||||
hovertemplate="<b>EXECUTED BUY TRADE</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
customdata=[t['confidence'] for t in buy_trades]
|
||||
),
|
||||
row=row, col=1
|
||||
)
|
||||
),
|
||||
row=row, col=1
|
||||
)
|
||||
|
||||
# Add EXECUTED SELL trades (large red circles)
|
||||
if sell_trades:
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=[t['x'] for t in sell_trades],
|
||||
y=[t['y'] for t in sell_trades],
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
symbol='circle',
|
||||
size=15,
|
||||
color='rgba(255, 100, 100, 0.9)',
|
||||
line=dict(width=3, color='red')
|
||||
),
|
||||
name='EXECUTED SELL',
|
||||
showlegend=True,
|
||||
hovertemplate="<b>EXECUTED SELL TRADE</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
name='EXECUTED SELL',
|
||||
showlegend=True,
|
||||
hovertemplate="<b>EXECUTED SELL TRADE</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
customdata=[t['confidence'] for t in sell_trades]
|
||||
),
|
||||
row=row, col=1
|
||||
)
|
||||
),
|
||||
row=row, col=1
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Error adding executed trades to main chart: {e}")
|
||||
@ -719,13 +738,13 @@ class CleanTradingDashboard:
|
||||
sell_signals = []
|
||||
|
||||
for signal in all_signals:
|
||||
signal_time = signal.get('timestamp')
|
||||
signal_price = signal.get('price', 0)
|
||||
signal_action = signal.get('action', 'HOLD')
|
||||
signal_confidence = signal.get('confidence', 0)
|
||||
is_executed = signal.get('executed', False)
|
||||
signal_time = self._get_signal_attribute(signal, 'timestamp')
|
||||
signal_price = self._get_signal_attribute(signal, 'price', 0)
|
||||
signal_action = self._get_signal_attribute(signal, 'action', 'HOLD')
|
||||
signal_confidence = self._get_signal_attribute(signal, 'confidence', 0)
|
||||
is_executed = self._get_signal_attribute(signal, 'executed', False)
|
||||
|
||||
if signal_time and signal_price and signal_confidence > 0:
|
||||
if signal_time and signal_price and signal_confidence and signal_confidence > 0:
|
||||
# Convert timestamp if needed
|
||||
if isinstance(signal_time, str):
|
||||
try:
|
||||
@ -762,36 +781,36 @@ class CleanTradingDashboard:
|
||||
|
||||
# Executed buy signals (solid green triangles)
|
||||
if executed_buys:
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=[s['x'] for s in executed_buys],
|
||||
y=[s['y'] for s in executed_buys],
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
symbol='triangle-up',
|
||||
size=10,
|
||||
size=10,
|
||||
color='rgba(0, 255, 100, 1.0)',
|
||||
line=dict(width=2, color='green')
|
||||
),
|
||||
name='BUY (Executed)',
|
||||
showlegend=False,
|
||||
hovertemplate="<b>BUY EXECUTED</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
customdata=[s['confidence'] for s in executed_buys]
|
||||
),
|
||||
row=row, col=1
|
||||
)
|
||||
),
|
||||
row=row, col=1
|
||||
)
|
||||
|
||||
# Pending/non-executed buy signals (hollow green triangles)
|
||||
if pending_buys:
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=[s['x'] for s in pending_buys],
|
||||
y=[s['y'] for s in pending_buys],
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
symbol='triangle-up',
|
||||
size=8,
|
||||
color='rgba(0, 255, 100, 0.5)',
|
||||
@ -823,20 +842,20 @@ class CleanTradingDashboard:
|
||||
mode='markers',
|
||||
marker=dict(
|
||||
symbol='triangle-down',
|
||||
size=10,
|
||||
size=10,
|
||||
color='rgba(255, 100, 100, 1.0)',
|
||||
line=dict(width=2, color='red')
|
||||
),
|
||||
name='SELL (Executed)',
|
||||
showlegend=False,
|
||||
hovertemplate="<b>SELL EXECUTED</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
customdata=[s['confidence'] for s in executed_sells]
|
||||
),
|
||||
row=row, col=1
|
||||
)
|
||||
),
|
||||
row=row, col=1
|
||||
)
|
||||
|
||||
# Pending/non-executed sell signals (hollow red triangles)
|
||||
if pending_sells:
|
||||
@ -1869,6 +1888,20 @@ class CleanTradingDashboard:
|
||||
except Exception as e:
|
||||
logger.error(f"Error clearing session: {e}")
|
||||
|
||||
def _get_signal_attribute(self, signal, attr_name, default=None):
|
||||
"""Safely get attribute from signal (handles both dict and dataclass objects)"""
|
||||
try:
|
||||
if hasattr(signal, attr_name):
|
||||
# Dataclass or object with attribute
|
||||
return getattr(signal, attr_name, default)
|
||||
elif isinstance(signal, dict):
|
||||
# Dictionary
|
||||
return signal.get(attr_name, default)
|
||||
else:
|
||||
return default
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
def _clear_old_signals_for_tick_range(self):
|
||||
"""Clear old signals that are outside the current tick cache time range"""
|
||||
try:
|
||||
@ -1883,7 +1916,7 @@ class CleanTradingDashboard:
|
||||
# Filter recent_decisions to only keep signals within the tick cache time range
|
||||
filtered_decisions = []
|
||||
for signal in self.recent_decisions:
|
||||
signal_time = signal.get('timestamp')
|
||||
signal_time = self._get_signal_attribute(signal, 'timestamp')
|
||||
if signal_time:
|
||||
# Convert signal timestamp to datetime for comparison
|
||||
try:
|
||||
|
Reference in New Issue
Block a user