TradingAgents/tests/portfolio/test_analytics.py

181 lines
6.2 KiB
Python

"""
Tests for performance analytics.
"""
import unittest
from decimal import Decimal
from datetime import datetime, timedelta
from tradingagents.portfolio import PerformanceAnalytics, TradeRecord
from tradingagents.portfolio.exceptions import ValidationError, CalculationError
class TestPerformanceAnalytics(unittest.TestCase):
"""Test cases for PerformanceAnalytics."""
def setUp(self):
"""Set up test analytics."""
self.analytics = PerformanceAnalytics()
def test_calculate_returns(self):
"""Test returns calculation from equity curve."""
equity_curve = [
(datetime(2024, 1, 1), Decimal('100000')),
(datetime(2024, 1, 2), Decimal('101000')),
(datetime(2024, 1, 3), Decimal('102000')),
]
returns = self.analytics.calculate_returns(equity_curve)
self.assertEqual(len(returns), 2)
# First return: (101000 - 100000) / 100000 = 0.01
self.assertEqual(returns[0], Decimal('0.01'))
def test_calculate_total_return(self):
"""Test total return calculation."""
initial = Decimal('100000')
final = Decimal('120000')
total_return = self.analytics.calculate_total_return(initial, final)
# (120000 - 100000) / 100000 = 0.20 (20%)
self.assertEqual(total_return, Decimal('0.20'))
def test_calculate_annualized_return(self):
"""Test annualized return calculation."""
total_return = Decimal('0.20') # 20% total
days = 365 # Over one year
annualized = self.analytics.calculate_annualized_return(total_return, days)
# Should be approximately 20% for one year
self.assertAlmostEqual(float(annualized), 0.20, places=2)
def test_calculate_volatility(self):
"""Test volatility calculation."""
# Create some returns with variation
returns = [Decimal('0.01'), Decimal('-0.01'), Decimal('0.02')] * 84 # 252 days
volatility = self.analytics.calculate_volatility(returns)
# Should be a positive number
self.assertGreater(volatility, 0)
def test_calculate_trade_statistics_empty(self):
"""Test trade statistics with no trades."""
stats = self.analytics.calculate_trade_statistics([])
self.assertEqual(stats['total_trades'], 0)
self.assertEqual(stats['win_rate'], Decimal('0'))
def test_calculate_trade_statistics_with_trades(self):
"""Test trade statistics with trades."""
trades = [
TradeRecord(
ticker='AAPL',
entry_date=datetime(2024, 1, 1),
exit_date=datetime(2024, 1, 10),
entry_price=Decimal('150'),
exit_price=Decimal('160'),
quantity=Decimal('100'),
pnl=Decimal('1000'),
pnl_percent=Decimal('0.067'),
commission=Decimal('15'),
holding_period=9,
is_win=True
),
TradeRecord(
ticker='GOOGL',
entry_date=datetime(2024, 1, 5),
exit_date=datetime(2024, 1, 15),
entry_price=Decimal('2000'),
exit_price=Decimal('1950'),
quantity=Decimal('50'),
pnl=Decimal('-2500'),
pnl_percent=Decimal('-0.025'),
commission=Decimal('100'),
holding_period=10,
is_win=False
),
]
stats = self.analytics.calculate_trade_statistics(trades)
self.assertEqual(stats['total_trades'], 2)
self.assertEqual(stats['winning_trades'], 1)
self.assertEqual(stats['losing_trades'], 1)
self.assertEqual(stats['win_rate'], Decimal('0.5'))
self.assertGreater(stats['average_win'], 0)
self.assertGreater(stats['average_loss'], 0)
def test_generate_performance_metrics(self):
"""Test comprehensive performance metrics generation."""
# Create sample equity curve
base_date = datetime(2024, 1, 1)
equity_curve = [
(base_date + timedelta(days=i), Decimal('100000') + Decimal(i * 100))
for i in range(30)
]
# Create sample trades
trades = [
TradeRecord(
ticker='AAPL',
entry_date=datetime(2024, 1, 1),
exit_date=datetime(2024, 1, 10),
entry_price=Decimal('150'),
exit_price=Decimal('160'),
quantity=Decimal('100'),
pnl=Decimal('1000'),
pnl_percent=Decimal('0.067'),
commission=Decimal('15'),
holding_period=9,
is_win=True
),
]
metrics = self.analytics.generate_performance_metrics(
equity_curve,
trades,
Decimal('100000')
)
self.assertIsNotNone(metrics.total_return)
self.assertIsNotNone(metrics.sharpe_ratio)
self.assertIsNotNone(metrics.max_drawdown)
self.assertEqual(metrics.total_trades, 1)
def test_calculate_monthly_returns(self):
"""Test monthly returns calculation."""
equity_curve = [
(datetime(2024, 1, 1), Decimal('100000')),
(datetime(2024, 1, 15), Decimal('105000')),
(datetime(2024, 1, 31), Decimal('110000')),
(datetime(2024, 2, 15), Decimal('115000')),
(datetime(2024, 2, 29), Decimal('120000')),
]
monthly_returns = self.analytics.calculate_monthly_returns(equity_curve)
self.assertIn('2024-01', monthly_returns)
self.assertIn('2024-02', monthly_returns)
def test_equity_curve_summary(self):
"""Test equity curve summary."""
equity_curve = [
(datetime(2024, 1, 1), Decimal('100000')),
(datetime(2024, 1, 15), Decimal('105000')),
(datetime(2024, 1, 31), Decimal('110000')),
]
summary = self.analytics.generate_equity_curve_summary(equity_curve)
self.assertEqual(summary['start_value'], '100000')
self.assertEqual(summary['end_value'], '110000')
self.assertEqual(summary['peak_value'], '110000')
self.assertEqual(summary['data_points'], 3)
if __name__ == '__main__':
unittest.main()