recent trades in list
This commit is contained in:
parent
989e755264
commit
3eff11fd78
46
access_app.py
Normal file
46
access_app.py
Normal file
@ -0,0 +1,46 @@
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
# Add the project root to the path
|
||||
sys.path.append(os.getcwd())
|
||||
|
||||
# Try to access the running application's charts
|
||||
from train_rl_with_realtime import charts
|
||||
|
||||
if not charts:
|
||||
print("No charts are running. Please start the application first.")
|
||||
sys.exit(1)
|
||||
|
||||
# Get the first chart
|
||||
chart = charts[0]
|
||||
print(f"Accessing chart for {chart.symbol}")
|
||||
|
||||
# Add some test trades
|
||||
print("Adding trades...")
|
||||
chart.add_trade(price=64500, timestamp=datetime.now(), pnl=0.5, action='BUY')
|
||||
print("Added BUY trade 1")
|
||||
time.sleep(1)
|
||||
chart.add_trade(price=64800, timestamp=datetime.now(), pnl=0.7, action='SELL')
|
||||
print("Added SELL trade 1")
|
||||
time.sleep(1)
|
||||
chart.add_trade(price=64600, timestamp=datetime.now(), pnl=0.3, action='BUY')
|
||||
print("Added BUY trade 2")
|
||||
time.sleep(1)
|
||||
chart.add_trade(price=64900, timestamp=datetime.now(), pnl=0.6, action='SELL')
|
||||
print("Added SELL trade 2")
|
||||
|
||||
# Try to get the current trades
|
||||
print("\nCurrent trades:")
|
||||
if hasattr(chart, 'trades') and chart.trades:
|
||||
for i, trade in enumerate(chart.trades[-5:]):
|
||||
action = trade.get('action', 'UNKNOWN')
|
||||
price = trade.get('price', 'N/A')
|
||||
timestamp = trade.get('timestamp', 'N/A')
|
||||
pnl = trade.get('pnl', None)
|
||||
close_price = trade.get('close_price', 'N/A')
|
||||
|
||||
print(f"Trade {i+1}: {action} @ {price}, Close: {close_price}, PnL: {pnl}, Time: {timestamp}")
|
||||
else:
|
||||
print("No trades found.")
|
53
add_test_trades.py
Normal file
53
add_test_trades.py
Normal file
@ -0,0 +1,53 @@
|
||||
from datetime import datetime, timedelta
|
||||
import random
|
||||
import time
|
||||
from realtime import RealTimeChart
|
||||
|
||||
# Create a standalone chart instance
|
||||
chart = RealTimeChart('BTC/USDT')
|
||||
|
||||
# Base price
|
||||
base_price = 65000.0
|
||||
|
||||
# Add 5 pairs of trades (BUY followed by SELL)
|
||||
for i in range(5):
|
||||
# Create a buy trade
|
||||
buy_price = base_price + random.uniform(-200, 200)
|
||||
buy_time = datetime.now() - timedelta(minutes=5-i) # Older to newer
|
||||
buy_amount = round(random.uniform(0.05, 0.5), 2)
|
||||
|
||||
# Add the BUY trade
|
||||
chart.add_trade(
|
||||
price=buy_price,
|
||||
timestamp=buy_time,
|
||||
amount=buy_amount,
|
||||
pnl=None, # Set to None for buys
|
||||
action='BUY'
|
||||
)
|
||||
print(f"Added BUY trade {i+1}: Price={buy_price:.2f}, Amount={buy_amount}, Time={buy_time}")
|
||||
|
||||
# Wait a moment
|
||||
time.sleep(0.5)
|
||||
|
||||
# Create a sell trade (typically at a different price)
|
||||
price_change = random.uniform(-100, 300) # More likely to be positive for profit
|
||||
sell_price = buy_price + price_change
|
||||
sell_time = buy_time + timedelta(minutes=random.uniform(0.5, 1.5))
|
||||
|
||||
# Calculate PnL
|
||||
pnl = (sell_price - buy_price) * buy_amount
|
||||
|
||||
# Add the SELL trade
|
||||
chart.add_trade(
|
||||
price=sell_price,
|
||||
timestamp=sell_time,
|
||||
amount=buy_amount, # Same amount as buy
|
||||
pnl=pnl,
|
||||
action='SELL'
|
||||
)
|
||||
print(f"Added SELL trade {i+1}: Price={sell_price:.2f}, PnL={pnl:.2f}, Time={sell_time}")
|
||||
|
||||
# Wait a moment before the next pair
|
||||
time.sleep(0.5)
|
||||
|
||||
print("\nAll trades added successfully!")
|
11
generate_trades.py
Normal file
11
generate_trades.py
Normal file
@ -0,0 +1,11 @@
|
||||
from datetime import datetime
|
||||
from realtime import RealTimeChart
|
||||
|
||||
chart = RealTimeChart('BTC/USDT')
|
||||
|
||||
for i in range(3):
|
||||
chart.add_trade(price=65000+i*100, timestamp=datetime.now(), pnl=0.1*i, action='BUY')
|
||||
chart.add_trade(price=65100+i*100, timestamp=datetime.now(), pnl=0.2*i, action='SELL')
|
||||
print(f'Added trade pair {i+1}')
|
||||
|
||||
print('All trades added successfully')
|
189
realtime.py
189
realtime.py
@ -1519,7 +1519,7 @@ class RealTimeChart:
|
||||
'color': '#FFFFFF',
|
||||
'backgroundColor': '#222'
|
||||
})
|
||||
], style={'marginTop': '20px', 'marginBottom': '20px', 'overflowX': 'auto'})
|
||||
], style={'marginTop': '20px', 'marginBottom': '20px', 'overflowX': 'auto'}),
|
||||
|
||||
# Chart acknowledgment
|
||||
html.Div("Real-time trading chart with ML signals", style={
|
||||
@ -2344,42 +2344,177 @@ class RealTimeChart:
|
||||
def _setup_position_list_callback(self):
|
||||
"""Callback to update the position list with the latest 5 trades"""
|
||||
@self.app.callback(
|
||||
Output('position-list', 'children'),
|
||||
Output('position-table-body', 'children'),
|
||||
[Input('interval-component', 'n_intervals')]
|
||||
)
|
||||
def update_position_list(n):
|
||||
try:
|
||||
# Get the last 5 positions
|
||||
if not hasattr(self, 'trades') or not self.trades:
|
||||
return [html.Li("No trades yet", style={'color': '#AAAAAA'})]
|
||||
|
||||
last_positions = self.trades[-5:]
|
||||
position_items = []
|
||||
return [html.Tr([html.Td("No trades yet", colSpan=6, style={'textAlign': 'center', 'color': '#AAAAAA', 'padding': '10px'})])]
|
||||
|
||||
for trade in last_positions:
|
||||
# Collect BUY and SELL trades to pair them
|
||||
buy_trades = {}
|
||||
sell_trades = {}
|
||||
position_rows = []
|
||||
|
||||
# Process all trades to match buy and sell pairs
|
||||
for trade in self.trades:
|
||||
action = trade.get('action', 'UNKNOWN')
|
||||
price = trade.get('price', 'N/A')
|
||||
timestamp = trade.get('timestamp', 'N/A')
|
||||
pnl = trade.get('pnl', None)
|
||||
|
||||
# Format the display
|
||||
pnl_str = f", PnL: {pnl:.4f}" if pnl is not None else ""
|
||||
time_str = timestamp.strftime('%H:%M:%S') if isinstance(timestamp, datetime) else str(timestamp)
|
||||
|
||||
# Set color based on action
|
||||
color = '#00FF00' if action == 'BUY' else '#FF0000'
|
||||
|
||||
position_items.append(
|
||||
html.Li(
|
||||
f"{action} @ {price} ({time_str}){pnl_str}",
|
||||
style={'color': color, 'padding': '5px', 'borderBottom': '1px solid #333'}
|
||||
)
|
||||
)
|
||||
if action == 'BUY':
|
||||
# Store buy trades by timestamp to match with sells later
|
||||
buy_trades[trade.get('timestamp')] = trade
|
||||
elif action == 'SELL':
|
||||
# Store sell trades
|
||||
sell_trades[trade.get('timestamp')] = trade
|
||||
|
||||
return position_items
|
||||
# Create position entries (matched pairs or single trades)
|
||||
position_entries = []
|
||||
|
||||
# First add matched pairs (BUY trades with matching close_price)
|
||||
for timestamp, buy_trade in buy_trades.items():
|
||||
if 'close_price' in buy_trade:
|
||||
# This is a closed position
|
||||
entry_price = buy_trade.get('price', 'N/A')
|
||||
exit_price = buy_trade.get('close_price', 'N/A')
|
||||
entry_time = buy_trade.get('timestamp')
|
||||
exit_time = buy_trade.get('close_timestamp')
|
||||
amount = buy_trade.get('amount', 0.1)
|
||||
|
||||
# Calculate PnL if not provided
|
||||
pnl = buy_trade.get('pnl')
|
||||
if pnl is None and isinstance(entry_price, (int, float)) and isinstance(exit_price, (int, float)):
|
||||
pnl = (exit_price - entry_price) * amount
|
||||
|
||||
position_entries.append({
|
||||
'action': 'CLOSED',
|
||||
'entry_price': entry_price,
|
||||
'exit_price': exit_price,
|
||||
'amount': amount,
|
||||
'pnl': pnl,
|
||||
'time': entry_time,
|
||||
'exit_time': exit_time,
|
||||
'status': 'CLOSED'
|
||||
})
|
||||
else:
|
||||
# This is an open position (BUY without a matching SELL)
|
||||
current_price = self.tick_storage.get_latest_price() or buy_trade.get('price', 0)
|
||||
amount = buy_trade.get('amount', 0.1)
|
||||
entry_price = buy_trade.get('price', 0)
|
||||
|
||||
# Calculate unrealized PnL
|
||||
unrealized_pnl = (current_price - entry_price) * amount if isinstance(current_price, (int, float)) and isinstance(entry_price, (int, float)) else None
|
||||
|
||||
position_entries.append({
|
||||
'action': 'BUY',
|
||||
'entry_price': entry_price,
|
||||
'exit_price': current_price, # Use current price as potential exit
|
||||
'amount': amount,
|
||||
'pnl': unrealized_pnl,
|
||||
'time': buy_trade.get('timestamp'),
|
||||
'status': 'OPEN'
|
||||
})
|
||||
|
||||
# Add standalone SELL trades that don't have a matching BUY
|
||||
for timestamp, sell_trade in sell_trades.items():
|
||||
# Check if this SELL is already accounted for in a closed position
|
||||
already_matched = False
|
||||
for entry in position_entries:
|
||||
if entry.get('status') == 'CLOSED' and entry.get('exit_time') == timestamp:
|
||||
already_matched = True
|
||||
break
|
||||
|
||||
if not already_matched:
|
||||
position_entries.append({
|
||||
'action': 'SELL',
|
||||
'entry_price': 'N/A',
|
||||
'exit_price': sell_trade.get('price', 'N/A'),
|
||||
'amount': sell_trade.get('amount', 0.1),
|
||||
'pnl': sell_trade.get('pnl'),
|
||||
'time': sell_trade.get('timestamp'),
|
||||
'status': 'STANDALONE'
|
||||
})
|
||||
|
||||
# Sort by time (most recent first) and take last 5
|
||||
position_entries.sort(key=lambda x: x['time'] if isinstance(x['time'], datetime) else datetime.now(), reverse=True)
|
||||
position_entries = position_entries[:5]
|
||||
|
||||
# Convert to table rows
|
||||
for entry in position_entries:
|
||||
action = entry['action']
|
||||
entry_price = entry['entry_price']
|
||||
exit_price = entry['exit_price']
|
||||
amount = entry['amount']
|
||||
pnl = entry['pnl']
|
||||
time_obj = entry['time']
|
||||
status = entry['status']
|
||||
|
||||
# Format time
|
||||
if isinstance(time_obj, datetime):
|
||||
# If trade is from a different day, include the date
|
||||
today = datetime.now().date()
|
||||
if time_obj.date() == today:
|
||||
time_str = time_obj.strftime('%H:%M:%S')
|
||||
else:
|
||||
time_str = time_obj.strftime('%m-%d %H:%M:%S')
|
||||
else:
|
||||
time_str = str(time_obj)
|
||||
|
||||
# Format prices with proper decimal places
|
||||
if isinstance(entry_price, (int, float)):
|
||||
entry_price_str = f"${entry_price:.2f}"
|
||||
else:
|
||||
entry_price_str = str(entry_price)
|
||||
|
||||
if isinstance(exit_price, (int, float)):
|
||||
exit_price_str = f"${exit_price:.2f}"
|
||||
else:
|
||||
exit_price_str = str(exit_price)
|
||||
|
||||
# Format PnL
|
||||
if pnl is not None and isinstance(pnl, (int, float)):
|
||||
pnl_str = f"${pnl:.2f}"
|
||||
pnl_color = '#00FF00' if pnl >= 0 else '#FF0000'
|
||||
else:
|
||||
pnl_str = 'N/A'
|
||||
pnl_color = '#FFFFFF'
|
||||
|
||||
# Set action/status color and text
|
||||
if status == 'OPEN':
|
||||
status_color = '#00AAFF' # Blue for open positions
|
||||
status_text = "OPEN (BUY)"
|
||||
elif status == 'CLOSED':
|
||||
if pnl is not None and isinstance(pnl, (int, float)):
|
||||
status_color = '#00FF00' if pnl >= 0 else '#FF0000' # Green/Red based on profit
|
||||
else:
|
||||
status_color = '#FFCC00' # Yellow if PnL unknown
|
||||
status_text = "CLOSED"
|
||||
elif action == 'BUY':
|
||||
status_color = '#00FF00'
|
||||
status_text = "BUY"
|
||||
elif action == 'SELL':
|
||||
status_color = '#FF0000'
|
||||
status_text = "SELL"
|
||||
else:
|
||||
status_color = '#FFFFFF'
|
||||
status_text = action
|
||||
|
||||
# Create table row
|
||||
position_rows.append(html.Tr([
|
||||
html.Td(status_text, style={'color': status_color, 'padding': '8px', 'border': '1px solid #444'}),
|
||||
html.Td(f"{amount} BTC", style={'padding': '8px', 'border': '1px solid #444'}),
|
||||
html.Td(entry_price_str, style={'padding': '8px', 'border': '1px solid #444'}),
|
||||
html.Td(exit_price_str, style={'padding': '8px', 'border': '1px solid #444'}),
|
||||
html.Td(pnl_str, style={'color': pnl_color, 'padding': '8px', 'border': '1px solid #444'}),
|
||||
html.Td(time_str, style={'padding': '8px', 'border': '1px solid #444'})
|
||||
]))
|
||||
|
||||
return position_rows
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating position list: {str(e)}")
|
||||
return [html.Li("Error loading positions", style={'color': '#FF0000'})]
|
||||
logger.error(f"Error updating position table: {str(e)}")
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
return [html.Tr([html.Td(f"Error: {str(e)}", colSpan=6, style={'color': '#FF0000', 'padding': '10px'})])]
|
||||
|
||||
def _interval_to_seconds(self, interval_key: str) -> int:
|
||||
"""Convert interval key to seconds"""
|
||||
|
50
test_timestamps.py
Normal file
50
test_timestamps.py
Normal file
@ -0,0 +1,50 @@
|
||||
from datetime import datetime, timedelta
|
||||
from realtime import RealTimeChart
|
||||
|
||||
# Create a chart instance
|
||||
chart = RealTimeChart('BTC/USDT')
|
||||
|
||||
# Add a BUY position from yesterday
|
||||
yesterday = datetime.now() - timedelta(days=1)
|
||||
chart.add_trade(
|
||||
price=64950.25,
|
||||
timestamp=yesterday,
|
||||
amount=0.5,
|
||||
pnl=None,
|
||||
action='BUY'
|
||||
)
|
||||
print(f'Added BUY position from {yesterday}')
|
||||
|
||||
# Add a matching SELL position from yesterday (2 hours later)
|
||||
yesterday_plus_2h = yesterday + timedelta(hours=2)
|
||||
chart.add_trade(
|
||||
price=65100.75,
|
||||
timestamp=yesterday_plus_2h,
|
||||
amount=0.5,
|
||||
pnl=75.25,
|
||||
action='SELL'
|
||||
)
|
||||
print(f'Added matching SELL position from {yesterday_plus_2h}')
|
||||
|
||||
# Add a trade from 2 days ago
|
||||
two_days_ago = datetime.now() - timedelta(days=2)
|
||||
chart.add_trade(
|
||||
price=64800.50,
|
||||
timestamp=two_days_ago,
|
||||
amount=0.25,
|
||||
pnl=None,
|
||||
action='BUY'
|
||||
)
|
||||
print(f'Added BUY position from {two_days_ago}')
|
||||
|
||||
two_days_ago_plus_3h = two_days_ago + timedelta(hours=3)
|
||||
chart.add_trade(
|
||||
price=65000.75,
|
||||
timestamp=two_days_ago_plus_3h,
|
||||
amount=0.25,
|
||||
pnl=50.06,
|
||||
action='SELL'
|
||||
)
|
||||
print(f'Added matching SELL position from {two_days_ago_plus_3h}')
|
||||
|
||||
print('\nAll test trades added successfully!')
|
Loading…
x
Reference in New Issue
Block a user