Local changes: Updated model training, removed debug instrumentation, and configuration improvements

This commit is contained in:
kfox
2025-12-26 01:15:43 -05:00
commit cc60da49e7
388 changed files with 57127 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
"""Integration tests."""

View File

@@ -0,0 +1,2 @@
"""Backend integration tests."""

View File

@@ -0,0 +1,95 @@
"""Integration tests for API workflows."""
import pytest
from fastapi.testclient import TestClient
from unittest.mock import patch, Mock
from backend.main import app
@pytest.fixture
def client():
"""Test client fixture."""
return TestClient(app)
@pytest.mark.integration
class TestTradingWorkflow:
"""Test complete trading workflow through API."""
@patch('backend.api.trading.get_trading_engine')
@patch('backend.api.trading.get_db')
def test_complete_trading_workflow(self, mock_get_db, mock_get_engine, client):
"""Test: Place order → Check order status → Get positions."""
# Setup mocks
mock_engine = Mock()
mock_order = Mock()
mock_order.id = 1
mock_order.symbol = "BTC/USD"
mock_order.side = "buy"
mock_order.status = "filled"
mock_engine.execute_order.return_value = mock_order
mock_get_engine.return_value = mock_engine
mock_db = Mock()
mock_session = Mock()
mock_db.get_session.return_value = mock_session
mock_get_db.return_value = mock_db
# Mock order query
mock_session.query.return_value.filter_by.return_value.order_by.return_value.limit.return_value.all.return_value = [mock_order]
mock_session.query.return_value.filter_by.return_value.first.return_value = mock_order
# Place order
order_data = {
"exchange_id": 1,
"symbol": "BTC/USD",
"side": "buy",
"order_type": "market",
"quantity": "0.1",
"paper_trading": True
}
create_response = client.post("/api/trading/orders", json=order_data)
assert create_response.status_code == 200
order_id = create_response.json()["id"]
# Get order status
status_response = client.get(f"/api/trading/orders/{order_id}")
assert status_response.status_code == 200
assert status_response.json()["id"] == order_id
# Get orders list
orders_response = client.get("/api/trading/orders")
assert orders_response.status_code == 200
assert isinstance(orders_response.json(), list)
@pytest.mark.integration
class TestPortfolioWorkflow:
"""Test portfolio workflow through API."""
@patch('backend.api.portfolio.get_portfolio_tracker')
def test_portfolio_workflow(self, mock_get_tracker, client):
"""Test: Get current portfolio → Get portfolio history."""
mock_tracker = Mock()
mock_tracker.get_current_portfolio.return_value = {
"positions": [],
"performance": {"total_return": 0.1},
"timestamp": "2025-01-01T00:00:00"
}
mock_tracker.get_portfolio_history.return_value = [
{"timestamp": "2025-01-01T00:00:00", "total_value": 1000.0, "total_pnl": 0.0}
]
mock_get_tracker.return_value = mock_tracker
# Get current portfolio
current_response = client.get("/api/portfolio/current?paper_trading=true")
assert current_response.status_code == 200
assert "positions" in current_response.json()
# Get portfolio history
history_response = client.get("/api/portfolio/history?paper_trading=true&days=30")
assert history_response.status_code == 200
assert "dates" in history_response.json()

View File

@@ -0,0 +1,323 @@
"""Integration tests for frontend API workflows.
These tests verify that all frontend-accessible API endpoints work correctly
and return data in the expected format for the React frontend.
"""
import pytest
from fastapi.testclient import TestClient
from decimal import Decimal
from datetime import datetime, timedelta
from unittest.mock import Mock, patch
from backend.main import app
@pytest.fixture
def client():
"""Create test client."""
return TestClient(app)
@pytest.fixture
def mock_strategy():
"""Mock strategy data."""
return {
"id": 1,
"name": "Test RSI Strategy",
"strategy_type": "rsi",
"class_name": "rsi",
"parameters": {
"symbol": "BTC/USD",
"exchange_id": 1,
"rsi_period": 14,
"oversold": 30,
"overbought": 70
},
"timeframes": ["1h"],
"enabled": False,
"paper_trading": True,
"version": "1.0.0",
"created_at": datetime.now().isoformat(),
"updated_at": datetime.now().isoformat()
}
@pytest.fixture
def mock_exchange():
"""Mock exchange data."""
return {
"id": 1,
"name": "coinbase",
"sandbox": False,
"read_only": True,
"enabled": True,
"created_at": datetime.now().isoformat(),
"updated_at": datetime.now().isoformat()
}
class TestStrategyManagementAPI:
"""Test strategy management API endpoints."""
def test_list_strategies(self, client):
"""Test listing all strategies."""
with patch('backend.api.strategies.get_db') as mock_db:
mock_session = Mock()
mock_strategy = Mock()
mock_strategy.id = 1
mock_strategy.name = "Test Strategy"
mock_strategy.strategy_type = "rsi"
mock_strategy.class_name = "rsi"
mock_strategy.parameters = {}
mock_strategy.timeframes = ["1h"]
mock_strategy.enabled = False
mock_strategy.paper_trading = True
mock_strategy.version = "1.0.0"
mock_strategy.description = None
mock_strategy.schedule = None
mock_strategy.created_at = datetime.now()
mock_strategy.updated_at = datetime.now()
mock_session.query.return_value.order_by.return_value.all.return_value = [mock_strategy]
mock_db.return_value.get_session.return_value.__enter__.return_value = mock_session
mock_db.return_value.get_session.return_value.__exit__ = Mock(return_value=None)
response = client.get("/api/strategies/")
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
def test_get_available_strategies(self, client):
"""Test getting available strategy types."""
with patch('backend.api.strategies.get_strategy_registry') as mock_registry:
mock_registry.return_value.list_available.return_value = [
"rsi", "macd", "moving_average", "dca", "grid", "momentum"
]
response = client.get("/api/strategies/available")
assert response.status_code == 200
data = response.json()
assert "strategies" in data
assert isinstance(data["strategies"], list)
def test_create_strategy(self, client, mock_strategy):
"""Test creating a new strategy."""
with patch('backend.api.strategies.get_db') as mock_db:
mock_session = Mock()
mock_db.return_value.get_session.return_value.__enter__.return_value = mock_session
mock_db.return_value.get_session.return_value.__exit__ = Mock(return_value=None)
mock_session.add = Mock()
mock_session.commit = Mock()
mock_session.refresh = Mock()
# Create strategy instance
created_strategy = Mock()
created_strategy.id = 1
created_strategy.name = mock_strategy["name"]
created_strategy.strategy_type = mock_strategy["strategy_type"]
created_strategy.class_name = mock_strategy["class_name"]
created_strategy.parameters = mock_strategy["parameters"]
created_strategy.timeframes = mock_strategy["timeframes"]
created_strategy.enabled = False
created_strategy.paper_trading = mock_strategy["paper_trading"]
created_strategy.version = "1.0.0"
created_strategy.description = None
created_strategy.schedule = None
created_strategy.created_at = datetime.now()
created_strategy.updated_at = datetime.now()
mock_session.refresh.side_effect = lambda x: setattr(x, 'id', 1)
response = client.post(
"/api/strategies/",
json={
"name": mock_strategy["name"],
"strategy_type": mock_strategy["strategy_type"],
"class_name": mock_strategy["class_name"],
"parameters": mock_strategy["parameters"],
"timeframes": mock_strategy["timeframes"],
"paper_trading": mock_strategy["paper_trading"]
}
)
# May return 200 or 500 depending on implementation
assert response.status_code in [200, 201, 500]
class TestTradingAPI:
"""Test trading API endpoints."""
def test_get_positions(self, client):
"""Test getting positions."""
with patch('src.trading.paper_trading.get_paper_trading') as mock_pt:
mock_pt.return_value.get_positions.return_value = []
response = client.get("/api/trading/positions?paper_trading=true")
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
def test_get_orders(self, client):
"""Test getting orders."""
with patch('backend.api.trading.get_db') as mock_db:
mock_session = Mock()
mock_session.query.return_value.filter_by.return_value.order_by.return_value.limit.return_value.all.return_value = []
mock_db.return_value.get_session.return_value.__enter__.return_value = mock_session
mock_db.return_value.get_session.return_value.__exit__ = Mock(return_value=None)
response = client.get("/api/trading/orders?paper_trading=true&limit=10")
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
def test_get_balance(self, client):
"""Test getting balance."""
with patch('src.trading.paper_trading.get_paper_trading') as mock_pt:
mock_pt.return_value.get_balance.return_value = Decimal("100.00")
mock_pt.return_value.get_performance.return_value = {}
response = client.get("/api/trading/balance?paper_trading=true")
assert response.status_code == 200
data = response.json()
assert "balance" in data
class TestPortfolioAPI:
"""Test portfolio API endpoints."""
def test_get_current_portfolio(self, client):
"""Test getting current portfolio."""
with patch('backend.api.portfolio.get_portfolio_tracker') as mock_tracker:
mock_tracker.return_value.get_current_portfolio.return_value = {
"positions": [],
"performance": {
"current_value": 100.0,
"unrealized_pnl": 0.0,
"realized_pnl": 0.0
},
"timestamp": datetime.now().isoformat()
}
response = client.get("/api/portfolio/current?paper_trading=true")
assert response.status_code == 200
data = response.json()
assert "positions" in data
assert "performance" in data
def test_get_portfolio_history(self, client):
"""Test getting portfolio history."""
with patch('backend.api.portfolio.get_portfolio_tracker') as mock_tracker:
mock_tracker.return_value.get_portfolio_history.return_value = {
"dates": [datetime.now().isoformat()],
"values": [100.0],
"pnl": [0.0]
}
response = client.get("/api/portfolio/history?days=30&paper_trading=true")
assert response.status_code == 200
data = response.json()
assert "dates" in data
assert "values" in data
class TestBacktestingAPI:
"""Test backtesting API endpoints."""
def test_run_backtest(self, client):
"""Test running a backtest."""
with patch('backend.api.backtesting.get_backtesting_engine') as mock_engine, \
patch('backend.api.backtesting.get_db') as mock_db:
mock_session = Mock()
mock_strategy = Mock()
mock_strategy.id = 1
mock_strategy.class_name = "rsi"
mock_strategy.parameters = {}
mock_strategy.timeframes = ["1h"]
mock_session.query.return_value.filter_by.return_value.first.return_value = mock_strategy
mock_db.return_value.get_session.return_value.__enter__.return_value = mock_session
mock_db.return_value.get_session.return_value.__exit__ = Mock(return_value=None)
mock_engine.return_value.run_backtest.return_value = {
"total_return": 0.1,
"sharpe_ratio": 1.5,
"max_drawdown": -0.05,
"win_rate": 0.6,
"total_trades": 10,
"final_value": 110.0
}
response = client.post(
"/api/backtesting/run",
json={
"strategy_id": 1,
"symbol": "BTC/USD",
"exchange": "coinbase",
"timeframe": "1h",
"start_date": (datetime.now() - timedelta(days=30)).isoformat(),
"end_date": datetime.now().isoformat(),
"initial_capital": 100.0,
"slippage": 0.001,
"fee_rate": 0.001
}
)
# May return 200 or error depending on implementation
assert response.status_code in [200, 400, 500]
class TestAlertsAPI:
"""Test alerts API endpoints."""
def test_list_alerts(self, client):
"""Test listing alerts."""
with patch('backend.api.alerts.get_alert_manager') as mock_manager:
mock_manager.return_value.list_alerts.return_value = []
response = client.get("/api/alerts/?enabled_only=false")
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
def test_create_alert(self, client):
"""Test creating an alert."""
with patch('backend.api.alerts.get_alert_manager') as mock_manager:
mock_alert = Mock()
mock_alert.id = 1
mock_alert.name = "Test Alert"
mock_alert.alert_type = "price"
mock_alert.condition = {"symbol": "BTC/USD", "price_threshold": 50000}
mock_alert.enabled = True
mock_alert.triggered = False
mock_alert.triggered_at = None
mock_alert.created_at = datetime.now()
mock_alert.updated_at = datetime.now()
mock_manager.return_value.create_alert.return_value = mock_alert
response = client.post(
"/api/alerts/",
json={
"name": "Test Alert",
"alert_type": "price",
"condition": {"symbol": "BTC/USD", "price_threshold": 50000}
}
)
# May return 200 or 500 depending on implementation
assert response.status_code in [200, 201, 500]
class TestExchangesAPI:
"""Test exchanges API endpoints."""
def test_list_exchanges(self, client):
"""Test listing exchanges."""
with patch('backend.api.exchanges.get_db') as mock_db:
mock_session = Mock()
mock_session.query.return_value.all.return_value = []
mock_db.return_value.get_session.return_value.__enter__.return_value = mock_session
mock_db.return_value.get_session.return_value.__exit__ = Mock(return_value=None)
response = client.get("/api/exchanges/")
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)

View File

@@ -0,0 +1,32 @@
"""Integration tests for WebSocket connections."""
import pytest
from fastapi.testclient import TestClient
from backend.main import app
@pytest.fixture
def client():
"""Test client fixture."""
return TestClient(app)
@pytest.mark.integration
class TestWebSocketConnection:
"""Test WebSocket connections."""
def test_websocket_connection(self, client):
"""Test WebSocket connection."""
with client.websocket_connect("/ws/") as websocket:
# Connection should be established
assert websocket is not None
def test_websocket_message_handling(self, client):
"""Test WebSocket message handling."""
with client.websocket_connect("/ws/") as websocket:
# Send a test message
websocket.send_json({"type": "ping"})
# WebSocket should accept the connection
# Note: Actual message handling depends on implementation

View File

@@ -0,0 +1,138 @@
"""Integration tests for autopilot workflows."""
import pytest
from unittest.mock import Mock, patch, AsyncMock
from fastapi.testclient import TestClient
from backend.main import app
@pytest.fixture
def client():
"""Test client fixture."""
return TestClient(app)
@pytest.fixture
def mock_intelligent_autopilot():
"""Mock intelligent autopilot."""
autopilot = Mock()
autopilot.symbol = "BTC/USD"
autopilot.is_running = False
autopilot.enable_auto_execution = False
autopilot.get_status.return_value = {
"symbol": "BTC/USD",
"timeframe": "1h",
"running": False,
"selected_strategy": None,
"trades_today": 0,
"max_trades_per_day": 10,
"min_confidence_threshold": 0.75,
"enable_auto_execution": False,
"last_analysis": None,
"model_info": {},
}
return autopilot
@pytest.mark.integration
class TestAutopilotWorkflow:
"""Integration tests for autopilot workflows."""
@patch('backend.api.autopilot.get_intelligent_autopilot')
def test_start_intelligent_mode_workflow(
self, mock_get_intelligent, client, mock_intelligent_autopilot
):
"""Test complete workflow for starting intelligent mode autopilot."""
mock_get_intelligent.return_value = mock_intelligent_autopilot
# Start autopilot
response = client.post(
"/api/autopilot/start-unified",
json={
"symbol": "BTC/USD",
"mode": "intelligent",
"auto_execute": True,
"exchange_id": 1,
"timeframe": "1h",
},
)
assert response.status_code == 200
assert mock_intelligent_autopilot.enable_auto_execution is True
# Check status
response = client.get(
"/api/autopilot/status-unified/BTC/USD?mode=intelligent&timeframe=1h"
)
assert response.status_code == 200
data = response.json()
assert data["mode"] == "intelligent"
# Stop autopilot
response = client.post(
"/api/autopilot/stop-unified?symbol=BTC/USD&mode=intelligent&timeframe=1h"
)
assert response.status_code == 200
assert mock_intelligent_autopilot.stop.called
@pytest.mark.integration
class TestTrainingConfigWorkflow:
"""Integration tests for training configuration workflow."""
def test_configure_and_verify_bootstrap(self, client):
"""Test configuring bootstrap settings and verifying they persist."""
# Set custom config
custom_config = {
"days": 180,
"timeframe": "4h",
"min_samples_per_strategy": 25,
"symbols": ["BTC/USD", "ETH/USD", "SOL/USD", "DOGE/USD"]
}
response = client.put("/api/autopilot/bootstrap-config", json=custom_config)
assert response.status_code == 200
# Verify it was saved
response = client.get("/api/autopilot/bootstrap-config")
assert response.status_code == 200
data = response.json()
assert data["days"] == 180
assert data["timeframe"] == "4h"
assert data["min_samples_per_strategy"] == 25
assert len(data["symbols"]) == 4
assert "DOGE/USD" in data["symbols"]
@patch('backend.api.autopilot.train_model_task')
def test_training_uses_configured_symbols(self, mock_task, client):
"""Test that training uses the configured symbols."""
# Setup mock
mock_result = Mock()
mock_result.id = "test-task-123"
mock_task.delay.return_value = mock_result
# Configure with specific symbols
config = {
"days": 90,
"timeframe": "1h",
"min_samples_per_strategy": 10,
"symbols": ["BTC/USD", "ETH/USD", "XRP/USD"]
}
client.put("/api/autopilot/bootstrap-config", json=config)
# Trigger training
response = client.post("/api/autopilot/intelligent/retrain")
assert response.status_code == 200
# Verify the symbols were passed
call_kwargs = mock_task.delay.call_args.kwargs
assert call_kwargs["symbols"] == ["BTC/USD", "ETH/USD", "XRP/USD"]
assert call_kwargs["days"] == 90
assert call_kwargs["timeframe"] == "1h"
assert call_kwargs["min_samples_per_strategy"] == 10

View File

@@ -0,0 +1,18 @@
"""Integration tests for backtesting workflow."""
import pytest
from datetime import datetime, timedelta
from src.backtesting.engine import get_backtest_engine
@pytest.mark.integration
class TestBacktestingWorkflow:
"""Integration tests for backtesting workflow."""
@pytest.mark.asyncio
async def test_backtesting_workflow(self):
"""Test complete backtesting workflow."""
engine = get_backtest_engine()
assert engine is not None
# Full workflow test would require strategy and data setup

View File

@@ -0,0 +1,21 @@
"""Integration tests for data pipeline."""
import pytest
from src.data.collector import get_data_collector
from src.data.storage import get_data_storage
@pytest.mark.integration
class TestDataPipeline:
"""Integration tests for data collection and storage."""
@pytest.mark.asyncio
async def test_data_collection_storage(self):
"""Test data collection and storage pipeline."""
collector = get_data_collector()
storage = get_data_storage()
# Test components exist
assert collector is not None
assert storage is not None

View File

@@ -0,0 +1,31 @@
"""Integration tests for portfolio tracking."""
import pytest
from decimal import Decimal
from src.portfolio.tracker import get_portfolio_tracker
from src.trading.paper_trading import get_paper_trading
@pytest.mark.integration
class TestPortfolioTracking:
"""Integration tests for portfolio tracking."""
@pytest.mark.asyncio
async def test_portfolio_tracking_workflow(self):
"""Test portfolio tracking workflow."""
tracker = get_portfolio_tracker()
paper_trading = get_paper_trading()
# Get initial portfolio
portfolio1 = await tracker.get_current_portfolio(paper_trading=True)
# Portfolio should have structure
assert "positions" in portfolio1
assert "performance" in portfolio1
# Get updated portfolio
portfolio2 = await tracker.get_current_portfolio(paper_trading=True)
# Should return valid portfolio
assert portfolio2 is not None

View File

@@ -0,0 +1,71 @@
"""Integration tests for pricing provider system."""
import pytest
from datetime import datetime
from src.data.pricing_service import get_pricing_service
@pytest.mark.integration
class TestPricingProviderIntegration:
"""Integration tests for pricing providers."""
@pytest.fixture(autouse=True)
def setup(self):
"""Set up test fixtures."""
# Reset global service instance
import src.data.pricing_service
src.data.pricing_service._pricing_service = None
def test_service_initialization(self):
"""Test that pricing service initializes correctly."""
service = get_pricing_service()
assert service is not None
assert service.cache is not None
assert service.health_monitor is not None
@pytest.mark.skip(reason="Requires network access - run manually")
def test_get_ticker_integration(self):
"""Test getting ticker data from real providers."""
service = get_pricing_service()
# This will try to connect to real providers
ticker = service.get_ticker("BTC/USD", use_cache=False)
# Should get some data if providers are available
if ticker:
assert 'symbol' in ticker
assert 'last' in ticker
assert ticker['last'] > 0
@pytest.mark.skip(reason="Requires network access - run manually")
def test_provider_failover(self):
"""Test provider failover mechanism."""
service = get_pricing_service()
# Get active provider
active = service.get_active_provider()
assert active is not None or len(service._providers) == 0
def test_cache_integration(self):
"""Test cache integration with service."""
service = get_pricing_service()
# Set a value
service.cache.set("test:key", "test_value", ttl=60)
# Get it back
value = service.cache.get("test:key")
assert value == "test_value"
def test_health_monitoring(self):
"""Test health monitoring integration."""
service = get_pricing_service()
# Record some metrics
service.health_monitor.record_success("test_provider", 0.5)
service.health_monitor.record_failure("test_provider")
# Check health
is_healthy = service.health_monitor.is_healthy("test_provider")
assert isinstance(is_healthy, bool)

View File

@@ -0,0 +1,36 @@
"""Integration tests for strategy execution."""
import pytest
from src.strategies.technical.rsi_strategy import RSIStrategy
from src.trading.engine import get_trading_engine
@pytest.mark.integration
class TestStrategyExecution:
"""Integration tests for strategy execution."""
@pytest.mark.asyncio
async def test_strategy_execution_workflow(self):
"""Test complete strategy execution workflow."""
engine = get_trading_engine()
await engine.initialize()
# Create strategy
strategy = RSIStrategy(
strategy_id=1,
name="test_rsi",
symbol="BTC/USD",
timeframe="1h",
parameters={"rsi_period": 14}
)
# Start strategy
await engine.start_strategy(strategy)
assert strategy.is_active
# Stop strategy
await engine.stop_strategy(1)
assert not strategy.is_active
await engine.shutdown()

View File

@@ -0,0 +1,47 @@
"""Integration tests for trading workflow."""
import pytest
from unittest.mock import Mock, AsyncMock, patch
from src.trading.engine import get_trading_engine
from src.strategies.technical.rsi_strategy import RSIStrategy
@pytest.mark.integration
class TestTradingWorkflow:
"""Integration tests for complete trading workflow."""
@pytest.mark.asyncio
async def test_complete_trading_workflow(self, mock_database):
"""Test complete trading workflow."""
# Initialize trading engine
engine = get_trading_engine()
await engine.initialize()
# Create strategy
strategy = RSIStrategy(
strategy_id=1,
name="test_rsi",
symbol="BTC/USD",
timeframe="1h",
parameters={"rsi_period": 14}
)
# Start strategy
await engine.start_strategy(strategy)
# Execute trade (paper trading)
result = await engine.execute_trade(
exchange_name="paper_trading",
strategy_id=1,
symbol="BTC/USD",
side="buy",
order_type="market",
amount=0.01,
is_paper_trade=True
)
assert result is not None
# Cleanup
await engine.shutdown()

View File

@@ -0,0 +1,65 @@
"""Integration tests for UI backtest workflow."""
import pytest
from datetime import datetime, timedelta
from PyQt6.QtWidgets import QApplication
from unittest.mock import Mock, patch
from src.ui.widgets.backtest_view import BacktestViewWidget
from src.strategies.technical.rsi_strategy import RSIStrategy
@pytest.fixture
def app():
"""Create QApplication for tests."""
if not QApplication.instance():
return QApplication([])
return QApplication.instance()
@pytest.fixture
def backtest_view(app):
"""Create BacktestViewWidget."""
view = BacktestViewWidget()
# Mock backtest engine
mock_engine = Mock()
mock_engine.run_backtest.return_value = {
'total_return': 10.5,
'sharpe_ratio': 1.2,
'max_drawdown': -5.0,
'win_rate': 0.55,
'total_trades': 50,
'final_value': 110.5,
'trades': []
}
view.backtest_engine = mock_engine
return view
def test_backtest_configuration(backtest_view):
"""Test backtest configuration form."""
assert backtest_view.strategy_combo is not None
assert backtest_view.symbol_input is not None
assert backtest_view.start_date is not None
assert backtest_view.end_date is not None
def test_backtest_results_display(backtest_view):
"""Test backtest results are displayed."""
results = {
'total_return': 10.5,
'sharpe_ratio': 1.2,
'max_drawdown': -5.0,
'win_rate': 0.55,
'total_trades': 50,
'final_value': 110.5,
'trades': []
}
backtest_view._display_results(results)
# Verify metrics text contains results
metrics_text = backtest_view.metrics_text.toPlainText()
assert "10.5" in metrics_text # Total return
assert "1.2" in metrics_text # Sharpe ratio

View File

@@ -0,0 +1,62 @@
"""Integration tests for UI strategy workflow."""
import pytest
from PyQt6.QtWidgets import QApplication
from unittest.mock import Mock, patch
from src.ui.widgets.strategy_manager import StrategyManagerWidget, StrategyDialog
from src.core.database import Strategy
@pytest.fixture
def app():
"""Create QApplication for tests."""
if not QApplication.instance():
return QApplication([])
return QApplication.instance()
@pytest.fixture
def strategy_manager(app):
"""Create StrategyManagerWidget."""
return StrategyManagerWidget()
def test_strategy_creation_workflow(strategy_manager, app):
"""Test creating strategy via UI."""
# Mock database
with patch.object(strategy_manager.db, 'get_session') as mock_session:
mock_session.return_value.__enter__.return_value.add = Mock()
mock_session.return_value.__enter__.return_value.commit = Mock()
# Simulate add strategy
dialog = StrategyDialog(strategy_manager)
dialog.name_input.setText("Test Strategy")
dialog.symbol_input.setText("BTC/USD")
dialog.type_combo.setCurrentText("rsi")
# Would need to set exchange combo data
# For now, just verify dialog structure
assert dialog.name_input.text() == "Test Strategy"
dialog.close()
def test_strategy_table_population(strategy_manager):
"""Test strategies table is populated from database."""
# Mock database query
mock_strategy = Mock(spec=Strategy)
mock_strategy.id = 1
mock_strategy.name = "Test Strategy"
mock_strategy.strategy_type = "rsi"
mock_strategy.parameters = {"symbol": "BTC/USD"}
mock_strategy.enabled = True
with patch.object(strategy_manager.db, 'get_session') as mock_session:
mock_query = Mock()
mock_query.all.return_value = [mock_strategy]
mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.all = Mock(return_value=[mock_strategy])
mock_session.return_value.__enter__.return_value.query.return_value.all = Mock(return_value=[mock_strategy])
strategy_manager._refresh_strategies()
# Verify table has data
# Note: Actual implementation would verify table contents

View File

@@ -0,0 +1,77 @@
"""Integration tests for UI trading workflow."""
import pytest
from decimal import Decimal
from PyQt6.QtWidgets import QApplication
from unittest.mock import Mock, patch
from src.ui.widgets.trading_view import TradingView
from src.core.database import Order, OrderStatus, OrderSide, OrderType
@pytest.fixture
def app():
"""Create QApplication for tests."""
if not QApplication.instance():
return QApplication([])
return QApplication.instance()
@pytest.fixture
def trading_view(app):
"""Create TradingView with mocked backend."""
view = TradingView()
# Mock trading engine
mock_engine = Mock()
mock_order = Mock(spec=Order)
mock_order.id = 1
mock_engine.execute_order.return_value = mock_order
view.trading_engine = mock_engine
return view
def test_order_placement_workflow(trading_view):
"""Test complete order placement workflow."""
# Set up form
trading_view.current_exchange_id = 1
trading_view.current_symbol = "BTC/USD"
trading_view.order_type_combo.setCurrentText("Market")
trading_view.side_combo.setCurrentText("Buy")
trading_view.quantity_input.setValue(0.1)
# Place order
trading_view._place_order()
# Verify engine was called
trading_view.trading_engine.execute_order.assert_called_once()
call_args = trading_view.trading_engine.execute_order.call_args
assert call_args[1]['symbol'] == "BTC/USD"
assert call_args[1]['side'] == OrderSide.BUY
def test_position_table_update(trading_view):
"""Test positions table updates with portfolio data."""
# Mock portfolio data
mock_portfolio = {
'positions': [
{
'symbol': 'BTC/USD',
'quantity': 0.1,
'entry_price': 50000,
'current_price': 51000,
'unrealized_pnl': 100
}
],
'performance': {
'current_value': 5100,
'unrealized_pnl': 100,
'realized_pnl': 0
}
}
trading_view.portfolio_tracker.get_current_portfolio = Mock(return_value=mock_portfolio)
trading_view._update_positions()
assert trading_view.positions_table.rowCount() == 1
assert trading_view.positions_table.item(0, 0).text() == "BTC/USD"