working actions dsplay, rewrite chart in realtime.py
This commit is contained in:
parent
902593b5f3
commit
44b02b4e7d
1731
realtime.py
1731
realtime.py
File diff suppressed because it is too large
Load Diff
173
realtime_old.py
173
realtime_old.py
@ -22,6 +22,7 @@ import tzlocal
|
|||||||
import threading
|
import threading
|
||||||
import random
|
import random
|
||||||
import dash_bootstrap_components as dbc
|
import dash_bootstrap_components as dbc
|
||||||
|
import uuid
|
||||||
|
|
||||||
# Configure logging with more detailed format
|
# Configure logging with more detailed format
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@ -2907,97 +2908,45 @@ class RealTimeChart:
|
|||||||
|
|
||||||
logger.info(f"Added NN signal: {signal_type} at {timestamp}")
|
logger.info(f"Added NN signal: {signal_type} at {timestamp}")
|
||||||
|
|
||||||
def add_trade(self, price, timestamp, pnl=None, amount=0.1, action=None, type=None):
|
def add_trade(self, price, timestamp, amount, pnl=0.0, action="BUY"):
|
||||||
"""Add a trade to be displayed on the chart
|
"""Add a trade to the chart and update the positions list"""
|
||||||
|
# Ensure the positions list exists
|
||||||
|
if not hasattr(self, 'positions'):
|
||||||
|
self.positions = []
|
||||||
|
|
||||||
Args:
|
# Create position ID
|
||||||
price: The price at which the trade was executed
|
position_id = str(uuid.uuid4())[:8]
|
||||||
timestamp: The timestamp for the trade
|
|
||||||
pnl: Optional profit and loss value for the trade
|
|
||||||
amount: Amount traded
|
|
||||||
action: The type of trade (BUY or SELL) - alternative to type parameter
|
|
||||||
type: The type of trade (BUY or SELL) - alternative to action parameter
|
|
||||||
"""
|
|
||||||
# Handle both action and type parameters for backward compatibility
|
|
||||||
trade_type = type or action
|
|
||||||
|
|
||||||
# Default to BUY if trade_type is None or not specified
|
# Log the trade
|
||||||
if trade_type is None:
|
logger.info(f"Added {action} trade: price={price}, amount={amount}, time={timestamp}, PnL={pnl}")
|
||||||
logger.warning(f"Trade type not specified in add_trade call, defaulting to BUY. Price: {price}, Timestamp: {timestamp}")
|
|
||||||
trade_type = "BUY"
|
|
||||||
|
|
||||||
if isinstance(trade_type, int):
|
# Add trade marker to the chart
|
||||||
trade_type = "BUY" if trade_type == 0 else "SELL"
|
if action == "BUY":
|
||||||
|
color = 'green'
|
||||||
|
marker = 'triangle-up'
|
||||||
|
else: # SELL
|
||||||
|
color = 'red'
|
||||||
|
marker = 'triangle-down'
|
||||||
|
|
||||||
# Ensure trade_type is uppercase if it's a string
|
# Add to positions list
|
||||||
if isinstance(trade_type, str):
|
new_position = Position(
|
||||||
trade_type = trade_type.upper()
|
action=action,
|
||||||
|
entry_price=price,
|
||||||
|
amount=amount,
|
||||||
|
timestamp=timestamp,
|
||||||
|
trade_id=position_id
|
||||||
|
)
|
||||||
|
self.positions.append(new_position)
|
||||||
|
|
||||||
if trade_type not in ['BUY', 'SELL']:
|
# Limit the positions list to the last 10 entries
|
||||||
logger.warning(f"Invalid trade type: {trade_type} (value type: {type(trade_type).__name__}), defaulting to BUY. Price: {price}, Timestamp: {timestamp}")
|
if len(self.positions) > 10:
|
||||||
trade_type = "BUY"
|
self.positions = self.positions[-10:]
|
||||||
|
|
||||||
# Convert timestamp to datetime if it's not already
|
# Add to the figure
|
||||||
if not isinstance(timestamp, datetime):
|
self._add_trade_marker(price, timestamp, color, marker)
|
||||||
try:
|
|
||||||
if isinstance(timestamp, str):
|
|
||||||
timestamp = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
|
|
||||||
elif isinstance(timestamp, (int, float)):
|
|
||||||
timestamp = datetime.fromtimestamp(timestamp / 1000.0)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error converting timestamp for trade: {str(e)}")
|
|
||||||
timestamp = datetime.now()
|
|
||||||
|
|
||||||
# Create the trade object
|
# Trigger update callback
|
||||||
trade = {
|
self._update_chart_and_positions()
|
||||||
'price': price,
|
|
||||||
'timestamp': timestamp,
|
|
||||||
'pnl': pnl,
|
|
||||||
'amount': amount,
|
|
||||||
'action': trade_type
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add to our trades list
|
|
||||||
if not hasattr(self, 'trades'):
|
|
||||||
self.trades = []
|
|
||||||
|
|
||||||
# If this is a SELL trade, try to find the corresponding BUY trade and update it with close_price
|
|
||||||
if trade_type == 'SELL' and len(self.trades) > 0:
|
|
||||||
for i in range(len(self.trades) - 1, -1, -1):
|
|
||||||
prev_trade = self.trades[i]
|
|
||||||
if prev_trade.get('action') == 'BUY' and 'close_price' not in prev_trade:
|
|
||||||
# Found a BUY trade without a close_price, consider it the matching trade
|
|
||||||
prev_trade['close_price'] = price
|
|
||||||
prev_trade['close_timestamp'] = timestamp
|
|
||||||
logger.info(f"Updated BUY trade at {prev_trade['timestamp']} with close price {price}")
|
|
||||||
break
|
|
||||||
|
|
||||||
self.trades.append(trade)
|
|
||||||
|
|
||||||
# Log the trade for debugging
|
|
||||||
pnl_str = f" with PnL: {pnl}" if pnl is not None else ""
|
|
||||||
logger.info(f"Added trade: {trade_type} {amount} at price {price} at time {timestamp}{pnl_str}")
|
|
||||||
|
|
||||||
# Trigger a more frequent update of the chart by scheduling a callback
|
|
||||||
# This helps ensure the trade appears immediately on the chart
|
|
||||||
if hasattr(self, 'app') and self.app is not None:
|
|
||||||
try:
|
|
||||||
# Only update if we have a dash app running
|
|
||||||
# This is a workaround to make trades appear immediately
|
|
||||||
callback_context = dash.callback_context
|
|
||||||
# Force an update by triggering the callback
|
|
||||||
for callback_id, callback_info in self.app.callback_map.items():
|
|
||||||
if 'live-chart' in callback_id:
|
|
||||||
# Found the chart callback, try to trigger it
|
|
||||||
logger.debug(f"Triggering chart update callback after trade")
|
|
||||||
callback_info['callback']()
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
# If callback triggering fails, it's not critical
|
|
||||||
logger.debug(f"Failed to trigger chart update: {str(e)}")
|
|
||||||
pass
|
|
||||||
|
|
||||||
return trade
|
|
||||||
|
|
||||||
def update_trading_info(self, signal=None, position=None, balance=None, pnl=None):
|
def update_trading_info(self, signal=None, position=None, balance=None, pnl=None):
|
||||||
"""Update the current trading information to be displayed on the chart
|
"""Update the current trading information to be displayed on the chart
|
||||||
@ -3026,6 +2975,62 @@ class RealTimeChart:
|
|||||||
|
|
||||||
logger.debug(f"Updated trading info: Signal={self.current_signal}, Position={self.current_position}, Balance=${self.session_balance:.2f}, PnL={self.session_pnl:.4f}")
|
logger.debug(f"Updated trading info: Signal={self.current_signal}, Position={self.current_position}, Balance=${self.session_balance:.2f}, PnL={self.session_pnl:.4f}")
|
||||||
|
|
||||||
|
def _add_trade_marker(self, price, timestamp, color, marker):
|
||||||
|
"""Add a trade marker to the chart
|
||||||
|
|
||||||
|
Args:
|
||||||
|
price: The price at which the trade was executed
|
||||||
|
timestamp: The timestamp for the trade
|
||||||
|
color: The color of the marker (green for buy, red for sell)
|
||||||
|
marker: The marker symbol to use (triangle-up for buy, triangle-down for sell)
|
||||||
|
"""
|
||||||
|
# Convert timestamp to datetime if it's not already
|
||||||
|
if not isinstance(timestamp, datetime):
|
||||||
|
try:
|
||||||
|
if isinstance(timestamp, str):
|
||||||
|
timestamp = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
|
||||||
|
elif isinstance(timestamp, (int, float)):
|
||||||
|
timestamp = datetime.fromtimestamp(timestamp / 1000.0)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error converting timestamp for trade marker: {str(e)}")
|
||||||
|
timestamp = datetime.now()
|
||||||
|
|
||||||
|
# Add marker to the figure
|
||||||
|
self.fig.add_trace(
|
||||||
|
go.Scatter(
|
||||||
|
x=[timestamp],
|
||||||
|
y=[price],
|
||||||
|
mode='markers',
|
||||||
|
name='BUY' if marker == 'triangle-up' else 'SELL',
|
||||||
|
marker=dict(
|
||||||
|
symbol=marker,
|
||||||
|
size=12,
|
||||||
|
color=f'rgba({0 if color == "green" else 255},{255 if color == "green" else 0},0,0.8)',
|
||||||
|
line=dict(width=1, color='darkgreen' if color == 'green' else 'darkred')
|
||||||
|
),
|
||||||
|
showlegend=True
|
||||||
|
),
|
||||||
|
row=1, col=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update the chart
|
||||||
|
self._update_chart_and_positions()
|
||||||
|
|
||||||
|
def _update_chart_and_positions(self):
|
||||||
|
"""Update the chart and positions list"""
|
||||||
|
try:
|
||||||
|
# Update the chart
|
||||||
|
self._update_chart()
|
||||||
|
|
||||||
|
# Update the positions list in the UI
|
||||||
|
if hasattr(self, 'app') and self.app is not None:
|
||||||
|
self.app.callback_context.triggered = [{'prop_id': 'interval-component.n_intervals'}]
|
||||||
|
self.app.callback_map['position-list.children']['callback']()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error updating chart and positions: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
global charts # Make charts globally accessible for NN integration
|
global charts # Make charts globally accessible for NN integration
|
||||||
symbols = ["ETH/USDT", "BTC/USDT"]
|
symbols = ["ETH/USDT", "BTC/USDT"]
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user