BIG CLEANUP

This commit is contained in:
Dobromir Popov
2025-08-08 14:58:55 +03:00
parent e39e9ee95a
commit 2b0d2679c6
162 changed files with 455 additions and 42814 deletions

View File

@@ -1,164 +0,0 @@
#!/usr/bin/env python3
"""
Test script to verify that both model prediction and trading statistics issues are fixed
"""
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from core.orchestrator import TradingOrchestrator
from core.data_provider import DataProvider
from core.trading_executor import TradingExecutor
import asyncio
import logging
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
async def test_model_predictions():
"""Test that model predictions are working correctly"""
logger.info("=" * 60)
logger.info("TESTING MODEL PREDICTIONS")
logger.info("=" * 60)
# Initialize components
data_provider = DataProvider()
orchestrator = TradingOrchestrator(data_provider)
# Check model registration
logger.info("1. Checking model registration...")
models = orchestrator.model_registry.get_all_models()
logger.info(f" Registered models: {list(models.keys()) if models else 'None'}")
# Test making a decision
logger.info("2. Testing trading decision generation...")
decision = await orchestrator.make_trading_decision('ETH/USDT')
if decision:
logger.info(f" ✅ Decision generated: {decision.action} (confidence: {decision.confidence:.3f})")
logger.info(f" ✅ Reasoning: {decision.reasoning}")
return True
else:
logger.error(" ❌ No decision generated")
return False
def test_trading_statistics():
"""Test that trading statistics calculations are working correctly"""
logger.info("=" * 60)
logger.info("TESTING TRADING STATISTICS")
logger.info("=" * 60)
# Initialize trading executor
trading_executor = TradingExecutor()
# Check if we have any trades
trade_history = trading_executor.get_trade_history()
logger.info(f"1. Current trade history: {len(trade_history)} trades")
# Get daily stats
daily_stats = trading_executor.get_daily_stats()
logger.info("2. Daily statistics from trading executor:")
logger.info(f" Total trades: {daily_stats.get('total_trades', 0)}")
logger.info(f" Winning trades: {daily_stats.get('winning_trades', 0)}")
logger.info(f" Losing trades: {daily_stats.get('losing_trades', 0)}")
logger.info(f" Win rate: {daily_stats.get('win_rate', 0.0) * 100:.1f}%")
logger.info(f" Avg winning trade: ${daily_stats.get('avg_winning_trade', 0.0):.2f}")
logger.info(f" Avg losing trade: ${daily_stats.get('avg_losing_trade', 0.0):.2f}")
logger.info(f" Total P&L: ${daily_stats.get('total_pnl', 0.0):.2f}")
# Simulate some trades if we don't have any
if daily_stats.get('total_trades', 0) == 0:
logger.info("3. No trades found - simulating some test trades...")
# Add some mock trades to the trade history
from core.trading_executor import TradeRecord
from datetime import datetime
# Add a winning trade
winning_trade = TradeRecord(
symbol='ETH/USDT',
side='LONG',
quantity=0.01,
entry_price=2500.0,
exit_price=2550.0,
entry_time=datetime.now(),
exit_time=datetime.now(),
pnl=0.50, # $0.50 profit
fees=0.01,
confidence=0.8
)
trading_executor.trade_history.append(winning_trade)
# Add a losing trade
losing_trade = TradeRecord(
symbol='ETH/USDT',
side='LONG',
quantity=0.01,
entry_price=2500.0,
exit_price=2480.0,
entry_time=datetime.now(),
exit_time=datetime.now(),
pnl=-0.20, # $0.20 loss
fees=0.01,
confidence=0.7
)
trading_executor.trade_history.append(losing_trade)
# Get updated stats
daily_stats = trading_executor.get_daily_stats()
logger.info(" Updated statistics after adding test trades:")
logger.info(f" Total trades: {daily_stats.get('total_trades', 0)}")
logger.info(f" Winning trades: {daily_stats.get('winning_trades', 0)}")
logger.info(f" Losing trades: {daily_stats.get('losing_trades', 0)}")
logger.info(f" Win rate: {daily_stats.get('win_rate', 0.0) * 100:.1f}%")
logger.info(f" Avg winning trade: ${daily_stats.get('avg_winning_trade', 0.0):.2f}")
logger.info(f" Avg losing trade: ${daily_stats.get('avg_losing_trade', 0.0):.2f}")
logger.info(f" Total P&L: ${daily_stats.get('total_pnl', 0.0):.2f}")
# Verify calculations
expected_win_rate = 1/2 # 1 win out of 2 trades = 50%
expected_avg_win = 0.50
expected_avg_loss = -0.20
actual_win_rate = daily_stats.get('win_rate', 0.0)
actual_avg_win = daily_stats.get('avg_winning_trade', 0.0)
actual_avg_loss = daily_stats.get('avg_losing_trade', 0.0)
logger.info("4. Verifying calculations:")
logger.info(f" Win rate: Expected {expected_win_rate*100:.1f}%, Got {actual_win_rate*100:.1f}% ✅" if abs(actual_win_rate - expected_win_rate) < 0.01 else f" Win rate: Expected {expected_win_rate*100:.1f}%, Got {actual_win_rate*100:.1f}% ❌")
logger.info(f" Avg win: Expected ${expected_avg_win:.2f}, Got ${actual_avg_win:.2f}" if abs(actual_avg_win - expected_avg_win) < 0.01 else f" Avg win: Expected ${expected_avg_win:.2f}, Got ${actual_avg_win:.2f}")
logger.info(f" Avg loss: Expected ${expected_avg_loss:.2f}, Got ${actual_avg_loss:.2f}" if abs(actual_avg_loss - expected_avg_loss) < 0.01 else f" Avg loss: Expected ${expected_avg_loss:.2f}, Got ${actual_avg_loss:.2f}")
return True
return True
async def main():
"""Run all tests"""
logger.info("🚀 STARTING COMPREHENSIVE FIXES TEST")
logger.info("Testing both model prediction fixes and trading statistics fixes")
# Test model predictions
prediction_success = await test_model_predictions()
# Test trading statistics
stats_success = test_trading_statistics()
logger.info("=" * 60)
logger.info("TEST SUMMARY")
logger.info("=" * 60)
logger.info(f"Model Predictions: {'✅ FIXED' if prediction_success else '❌ STILL BROKEN'}")
logger.info(f"Trading Statistics: {'✅ FIXED' if stats_success else '❌ STILL BROKEN'}")
if prediction_success and stats_success:
logger.info("🎉 ALL ISSUES FIXED! The system should now work correctly.")
else:
logger.error("❌ Some issues remain. Check the logs above for details.")
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -1,250 +0,0 @@
#!/usr/bin/env python3
"""
Test script to verify trading fixes:
1. Position sizes with leverage
2. ETH-only trading
3. Correct win rate calculations
4. Meaningful P&L values
"""
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from core.trading_executor import TradingExecutor
from core.trading_executor import TradeRecord
from datetime import datetime
import logging
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def test_position_sizing():
"""Test that position sizing now includes leverage and meaningful amounts"""
logger.info("=" * 60)
logger.info("TESTING POSITION SIZING WITH LEVERAGE")
logger.info("=" * 60)
# Initialize trading executor
trading_executor = TradingExecutor()
# Test position calculation
confidence = 0.8
current_price = 2500.0 # ETH price
position_value = trading_executor._calculate_position_size(confidence, current_price)
quantity = position_value / current_price
logger.info(f"1. Position calculation test:")
logger.info(f" Confidence: {confidence}")
logger.info(f" ETH Price: ${current_price}")
logger.info(f" Position Value: ${position_value:.2f}")
logger.info(f" Quantity: {quantity:.6f} ETH")
# Check if position is meaningful
if position_value > 1000: # Should be >$1000 with 10x leverage
logger.info(" ✅ Position size is meaningful (>$1000)")
else:
logger.error(f" ❌ Position size too small: ${position_value:.2f}")
# Test different confidence levels
logger.info("2. Testing different confidence levels:")
for conf in [0.2, 0.5, 0.8, 1.0]:
pos_val = trading_executor._calculate_position_size(conf, current_price)
qty = pos_val / current_price
logger.info(f" Confidence {conf}: ${pos_val:.2f} ({qty:.6f} ETH)")
def test_eth_only_restriction():
"""Test that only ETH trades are allowed"""
logger.info("=" * 60)
logger.info("TESTING ETH-ONLY TRADING RESTRICTION")
logger.info("=" * 60)
trading_executor = TradingExecutor()
# Test ETH trade (should be allowed)
logger.info("1. Testing ETH/USDT trade (should be allowed):")
eth_allowed = trading_executor._check_safety_conditions('ETH/USDT', 'BUY')
logger.info(f" ETH/USDT allowed: {'✅ YES' if eth_allowed else '❌ NO'}")
# Test BTC trade (should be blocked)
logger.info("2. Testing BTC/USDT trade (should be blocked):")
btc_allowed = trading_executor._check_safety_conditions('BTC/USDT', 'BUY')
logger.info(f" BTC/USDT allowed: {'❌ YES (ERROR!)' if btc_allowed else '✅ NO (CORRECT)'}")
def test_win_rate_calculation():
"""Test that win rate calculations are correct"""
logger.info("=" * 60)
logger.info("TESTING WIN RATE CALCULATIONS")
logger.info("=" * 60)
trading_executor = TradingExecutor()
# Clear existing trades
trading_executor.trade_history = []
# Add test trades with meaningful P&L
logger.info("1. Adding test trades with meaningful P&L:")
# Add 3 winning trades
for i in range(3):
winning_trade = TradeRecord(
symbol='ETH/USDT',
side='LONG',
quantity=1.0,
entry_price=2500.0,
exit_price=2550.0,
entry_time=datetime.now(),
exit_time=datetime.now(),
pnl=50.0, # $50 profit with leverage
fees=1.0,
confidence=0.8,
hold_time_seconds=30.0 # 30 second hold
)
trading_executor.trade_history.append(winning_trade)
logger.info(f" Added winning trade #{i+1}: +$50.00 (30s hold)")
# Add 2 losing trades
for i in range(2):
losing_trade = TradeRecord(
symbol='ETH/USDT',
side='LONG',
quantity=1.0,
entry_price=2500.0,
exit_price=2475.0,
entry_time=datetime.now(),
exit_time=datetime.now(),
pnl=-25.0, # $25 loss with leverage
fees=1.0,
confidence=0.7,
hold_time_seconds=15.0 # 15 second hold
)
trading_executor.trade_history.append(losing_trade)
logger.info(f" Added losing trade #{i+1}: -$25.00 (15s hold)")
# Get statistics
stats = trading_executor.get_daily_stats()
logger.info("2. Calculated statistics:")
logger.info(f" Total trades: {stats['total_trades']}")
logger.info(f" Winning trades: {stats['winning_trades']}")
logger.info(f" Losing trades: {stats['losing_trades']}")
logger.info(f" Win rate: {stats['win_rate']*100:.1f}%")
logger.info(f" Avg winning trade: ${stats['avg_winning_trade']:.2f}")
logger.info(f" Avg losing trade: ${stats['avg_losing_trade']:.2f}")
logger.info(f" Total P&L: ${stats['total_pnl']:.2f}")
# Verify calculations
expected_win_rate = 3/5 # 3 wins out of 5 trades = 60%
expected_avg_win = 50.0
expected_avg_loss = -25.0
logger.info("3. Verification:")
win_rate_ok = abs(stats['win_rate'] - expected_win_rate) < 0.01
avg_win_ok = abs(stats['avg_winning_trade'] - expected_avg_win) < 0.01
avg_loss_ok = abs(stats['avg_losing_trade'] - expected_avg_loss) < 0.01
logger.info(f" Win rate: Expected {expected_win_rate*100:.1f}%, Got {stats['win_rate']*100:.1f}% {'' if win_rate_ok else ''}")
logger.info(f" Avg win: Expected ${expected_avg_win:.2f}, Got ${stats['avg_winning_trade']:.2f} {'' if avg_win_ok else ''}")
logger.info(f" Avg loss: Expected ${expected_avg_loss:.2f}, Got ${stats['avg_losing_trade']:.2f} {'' if avg_loss_ok else ''}")
return win_rate_ok and avg_win_ok and avg_loss_ok
def test_new_features():
"""Test new features: hold time, leverage, percentage-based sizing"""
logger.info("=" * 60)
logger.info("TESTING NEW FEATURES")
logger.info("=" * 60)
trading_executor = TradingExecutor()
# Test account info
account_info = trading_executor.get_account_info()
logger.info(f"1. Account Information:")
logger.info(f" Account Balance: ${account_info['account_balance']:.2f}")
logger.info(f" Leverage: {account_info['leverage']:.0f}x")
logger.info(f" Trading Mode: {account_info['trading_mode']}")
logger.info(f" Position Sizing: {account_info['position_sizing']['base_percent']:.1f}% base")
# Test leverage setting
logger.info("2. Testing leverage control:")
old_leverage = trading_executor.get_leverage()
logger.info(f" Current leverage: {old_leverage:.0f}x")
success = trading_executor.set_leverage(100.0)
new_leverage = trading_executor.get_leverage()
logger.info(f" Set to 100x: {'✅ SUCCESS' if success and new_leverage == 100.0 else '❌ FAILED'}")
# Reset leverage
trading_executor.set_leverage(old_leverage)
# Test percentage-based position sizing
logger.info("3. Testing percentage-based position sizing:")
confidence = 0.8
eth_price = 2500.0
position_value = trading_executor._calculate_position_size(confidence, eth_price)
account_balance = trading_executor._get_account_balance_for_sizing()
base_percent = trading_executor.mexc_config.get('base_position_percent', 5.0)
leverage = trading_executor.get_leverage()
expected_base = account_balance * (base_percent / 100.0) * confidence
expected_leveraged = expected_base * leverage
logger.info(f" Account: ${account_balance:.2f}")
logger.info(f" Base %: {base_percent:.1f}%")
logger.info(f" Confidence: {confidence:.1f}")
logger.info(f" Leverage: {leverage:.0f}x")
logger.info(f" Expected base: ${expected_base:.2f}")
logger.info(f" Expected leveraged: ${expected_leveraged:.2f}")
logger.info(f" Actual: ${position_value:.2f}")
sizing_ok = abs(position_value - expected_leveraged) < 0.01
logger.info(f" Percentage sizing: {'✅ CORRECT' if sizing_ok else '❌ INCORRECT'}")
return sizing_ok
def main():
"""Run all tests"""
logger.info("🚀 TESTING TRADING FIXES AND NEW FEATURES")
logger.info("Testing position sizing, ETH-only trading, win rate calculations, and new features")
# Test position sizing
test_position_sizing()
# Test ETH-only restriction
test_eth_only_restriction()
# Test win rate calculation
calculation_success = test_win_rate_calculation()
# Test new features
features_success = test_new_features()
logger.info("=" * 60)
logger.info("TEST SUMMARY")
logger.info("=" * 60)
logger.info(f"Position Sizing: ✅ Updated with percentage-based leverage")
logger.info(f"ETH-Only Trading: ✅ Configured in config")
logger.info(f"Win Rate Calculation: {'✅ FIXED' if calculation_success else '❌ STILL BROKEN'}")
logger.info(f"New Features: {'✅ WORKING' if features_success else '❌ ISSUES FOUND'}")
if calculation_success and features_success:
logger.info("🎉 ALL FEATURES WORKING! Now you should see:")
logger.info(" - Percentage-based position sizing (2-20% of account)")
logger.info(" - 50x leverage (adjustable in UI)")
logger.info(" - Hold time in seconds for each trade")
logger.info(" - Total fees in trading statistics")
logger.info(" - Only ETH/USDT trades")
logger.info(" - Correct win rate calculations")
else:
logger.error("❌ Some issues remain. Check the logs above for details.")
if __name__ == "__main__":
main()

View File

@@ -1,344 +0,0 @@
#!/usr/bin/env python3
"""
Trade Audit Tool
This tool analyzes trade data to identify potential issues with:
- Duplicate entry prices
- Rapid consecutive trades
- P&L calculation accuracy
- Position tracking problems
Usage:
python debug/trade_audit.py [--trades-file path/to/trades.json]
"""
import argparse
import json
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import os
import sys
from pathlib import Path
# Add project root to path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
def parse_trade_time(time_str):
"""Parse trade time string to datetime object"""
try:
# Try HH:MM:SS format
return datetime.strptime(time_str, "%H:%M:%S")
except ValueError:
try:
# Try full datetime format
return datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
except ValueError:
# Return as is if parsing fails
return time_str
def load_trades_from_file(file_path):
"""Load trades from JSON file"""
try:
with open(file_path, 'r') as f:
return json.load(f)
except FileNotFoundError:
print(f"Error: File {file_path} not found")
return []
except json.JSONDecodeError:
print(f"Error: File {file_path} is not valid JSON")
return []
def load_trades_from_dashboard_cache():
"""Load trades from dashboard cache file if available"""
cache_paths = [
"cache/dashboard_trades.json",
"cache/closed_trades.json",
"data/trades_history.json"
]
for path in cache_paths:
if os.path.exists(path):
print(f"Loading trades from cache: {path}")
return load_trades_from_file(path)
print("No trade cache files found")
return []
def parse_trade_data(trades_data):
"""Parse trade data into a pandas DataFrame for analysis"""
parsed_trades = []
for trade in trades_data:
# Handle different trade data formats
parsed_trade = {}
# Time field might be named entry_time or time
if 'entry_time' in trade:
parsed_trade['time'] = parse_trade_time(trade['entry_time'])
elif 'time' in trade:
parsed_trade['time'] = parse_trade_time(trade['time'])
else:
parsed_trade['time'] = None
# Side might be named side or action
parsed_trade['side'] = trade.get('side', trade.get('action', 'UNKNOWN'))
# Size might be named size or quantity
parsed_trade['size'] = float(trade.get('size', trade.get('quantity', 0)))
# Entry and exit prices
parsed_trade['entry_price'] = float(trade.get('entry_price', trade.get('entry', 0)))
parsed_trade['exit_price'] = float(trade.get('exit_price', trade.get('exit', 0)))
# Hold time in seconds
parsed_trade['hold_time'] = float(trade.get('hold_time_seconds', trade.get('hold', 0)))
# P&L and fees
parsed_trade['pnl'] = float(trade.get('pnl', 0))
parsed_trade['fees'] = float(trade.get('fees', 0))
# Calculate expected P&L for verification
if parsed_trade['side'] == 'LONG' or parsed_trade['side'] == 'BUY':
expected_pnl = (parsed_trade['exit_price'] - parsed_trade['entry_price']) * parsed_trade['size']
else: # SHORT or SELL
expected_pnl = (parsed_trade['entry_price'] - parsed_trade['exit_price']) * parsed_trade['size']
parsed_trade['expected_pnl'] = expected_pnl
parsed_trade['pnl_difference'] = parsed_trade['pnl'] - expected_pnl
parsed_trades.append(parsed_trade)
# Convert to DataFrame
if parsed_trades:
df = pd.DataFrame(parsed_trades)
return df
else:
return pd.DataFrame()
def analyze_trades(df):
"""Analyze trades for potential issues"""
if df.empty:
print("No trades to analyze")
return
print(f"\n{'='*50}")
print("TRADE AUDIT RESULTS")
print(f"{'='*50}")
print(f"Total trades analyzed: {len(df)}")
# Check for duplicate entry prices
entry_price_counts = df['entry_price'].value_counts()
duplicate_entries = entry_price_counts[entry_price_counts > 1]
print(f"\n{'='*20} DUPLICATE ENTRY PRICES {'='*20}")
if not duplicate_entries.empty:
print(f"Found {len(duplicate_entries)} prices with multiple entries:")
for price, count in duplicate_entries.items():
print(f" ${price:.2f}: {count} trades")
# Analyze the duplicate entry trades in more detail
for price in duplicate_entries.index:
duplicate_df = df[df['entry_price'] == price].copy()
duplicate_df['time_diff'] = duplicate_df['time'].diff().dt.total_seconds()
print(f"\nDetailed analysis for entry price ${price:.2f}:")
print(f" Time gaps between consecutive trades:")
for i, (_, row) in enumerate(duplicate_df.iterrows()):
if i > 0: # Skip first row as it has no previous trade
time_diff = row['time_diff']
if pd.notna(time_diff):
print(f" {row['time'].strftime('%H:%M:%S')}: {time_diff:.0f} seconds after previous trade")
else:
print("No duplicate entry prices found")
# Check for rapid consecutive trades
df = df.sort_values('time')
df['time_since_last'] = df['time'].diff().dt.total_seconds()
rapid_trades = df[df['time_since_last'] < 30].copy()
print(f"\n{'='*20} RAPID CONSECUTIVE TRADES {'='*20}")
if not rapid_trades.empty:
print(f"Found {len(rapid_trades)} trades executed within 30 seconds of previous trade:")
for _, row in rapid_trades.iterrows():
if pd.notna(row['time_since_last']):
print(f" {row['time'].strftime('%H:%M:%S')} - {row['side']} ${row['size']:.2f} @ ${row['entry_price']:.2f} - {row['time_since_last']:.0f}s after previous")
else:
print("No rapid consecutive trades found")
# Check for P&L calculation accuracy
pnl_diff = df[abs(df['pnl_difference']) > 0.01].copy()
print(f"\n{'='*20} P&L CALCULATION ISSUES {'='*20}")
if not pnl_diff.empty:
print(f"Found {len(pnl_diff)} trades with P&L calculation discrepancies:")
for _, row in pnl_diff.iterrows():
print(f" {row['time'].strftime('%H:%M:%S')} - {row['side']} - Reported: ${row['pnl']:.2f}, Expected: ${row['expected_pnl']:.2f}, Diff: ${row['pnl_difference']:.2f}")
else:
print("No P&L calculation issues found")
# Check for side distribution
side_counts = df['side'].value_counts()
print(f"\n{'='*20} TRADE SIDE DISTRIBUTION {'='*20}")
for side, count in side_counts.items():
print(f" {side}: {count} trades ({count/len(df)*100:.1f}%)")
# Check for hold time distribution
print(f"\n{'='*20} HOLD TIME DISTRIBUTION {'='*20}")
print(f" Min hold time: {df['hold_time'].min():.0f} seconds")
print(f" Max hold time: {df['hold_time'].max():.0f} seconds")
print(f" Avg hold time: {df['hold_time'].mean():.0f} seconds")
print(f" Median hold time: {df['hold_time'].median():.0f} seconds")
# Hold time buckets
hold_buckets = [0, 30, 60, 120, 300, 600, 1800, 3600, float('inf')]
hold_labels = ['0-30s', '30-60s', '1-2m', '2-5m', '5-10m', '10-30m', '30-60m', '60m+']
df['hold_bucket'] = pd.cut(df['hold_time'], bins=hold_buckets, labels=hold_labels)
hold_dist = df['hold_bucket'].value_counts().sort_index()
for bucket, count in hold_dist.items():
print(f" {bucket}: {count} trades ({count/len(df)*100:.1f}%)")
# Generate summary statistics
print(f"\n{'='*20} TRADE PERFORMANCE SUMMARY {'='*20}")
winning_trades = df[df['pnl'] > 0]
losing_trades = df[df['pnl'] < 0]
print(f" Win rate: {len(winning_trades)/len(df)*100:.1f}% ({len(winning_trades)}W/{len(losing_trades)}L)")
print(f" Avg win: ${winning_trades['pnl'].mean():.2f}")
print(f" Avg loss: ${abs(losing_trades['pnl'].mean()):.2f}")
print(f" Total P&L: ${df['pnl'].sum():.2f}")
print(f" Total fees: ${df['fees'].sum():.2f}")
print(f" Net P&L: ${(df['pnl'].sum() - df['fees'].sum()):.2f}")
# Plot entry price distribution
plt.figure(figsize=(10, 6))
plt.hist(df['entry_price'], bins=20, alpha=0.7)
plt.title('Entry Price Distribution')
plt.xlabel('Entry Price ($)')
plt.ylabel('Number of Trades')
plt.grid(True, alpha=0.3)
plt.savefig('debug/entry_price_distribution.png')
# Plot P&L distribution
plt.figure(figsize=(10, 6))
plt.hist(df['pnl'], bins=20, alpha=0.7)
plt.title('P&L Distribution')
plt.xlabel('P&L ($)')
plt.ylabel('Number of Trades')
plt.grid(True, alpha=0.3)
plt.savefig('debug/pnl_distribution.png')
print(f"\n{'='*20} AUDIT COMPLETE {'='*20}")
print("Plots saved to debug/entry_price_distribution.png and debug/pnl_distribution.png")
def analyze_manual_trades(trades_data):
"""Analyze manually provided trade data"""
# Parse the trade data into a structured format
parsed_trades = []
for line in trades_data.strip().split('\n'):
if not line or line.startswith('from last session') or line.startswith('Recent Closed Trades') or line.startswith('Trading Performance'):
continue
if line.startswith('Win Rate:'):
# This is the summary line, skip it
continue
try:
# Parse trade line format: Time Side Size Entry Exit Hold P&L Fees
parts = line.split('$')
time_side = parts[0].strip().split()
time = time_side[0]
side = time_side[1]
size = float(parts[1].split()[0])
entry = float(parts[2].split()[0])
exit = float(parts[3].split()[0])
# The hold time and P&L are in the last parts
remaining = parts[3].split()
hold = int(remaining[1])
pnl = float(parts[4].split()[0])
# Fees might be in a different format
if len(parts) > 5:
fees = float(parts[5].strip())
else:
fees = 0.0
parsed_trade = {
'time': parse_trade_time(time),
'side': side,
'size': size,
'entry_price': entry,
'exit_price': exit,
'hold_time': hold,
'pnl': pnl,
'fees': fees
}
# Calculate expected P&L
if side == 'LONG' or side == 'BUY':
expected_pnl = (exit - entry) * size
else: # SHORT or SELL
expected_pnl = (entry - exit) * size
parsed_trade['expected_pnl'] = expected_pnl
parsed_trade['pnl_difference'] = pnl - expected_pnl
parsed_trades.append(parsed_trade)
except Exception as e:
print(f"Error parsing trade line: {line}")
print(f"Error details: {e}")
# Convert to DataFrame
if parsed_trades:
df = pd.DataFrame(parsed_trades)
return df
else:
return pd.DataFrame()
def main():
parser = argparse.ArgumentParser(description='Trade Audit Tool')
parser.add_argument('--trades-file', type=str, help='Path to trades JSON file')
parser.add_argument('--manual-trades', type=str, help='Path to text file with manually entered trades')
args = parser.parse_args()
# Create debug directory if it doesn't exist
os.makedirs('debug', exist_ok=True)
if args.trades_file:
trades_data = load_trades_from_file(args.trades_file)
df = parse_trade_data(trades_data)
elif args.manual_trades:
try:
with open(args.manual_trades, 'r') as f:
manual_trades = f.read()
df = analyze_manual_trades(manual_trades)
except Exception as e:
print(f"Error reading manual trades file: {e}")
df = pd.DataFrame()
else:
# Try to load from dashboard cache
trades_data = load_trades_from_dashboard_cache()
if trades_data:
df = parse_trade_data(trades_data)
else:
print("No trade data provided. Use --trades-file or --manual-trades")
return
if not df.empty:
analyze_trades(df)
else:
print("No valid trade data to analyze")
if __name__ == "__main__":
main()