From 72d29b4798f2594465f384982f0fc932a1f6c880 Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:28:14 +0900 Subject: fix: lint cleanup for API, combined strategy, and formatting --- services/api/src/trading_api/main.py | 1 + services/api/src/trading_api/routers/orders.py | 1 + services/api/src/trading_api/routers/portfolio.py | 3 ++- services/api/src/trading_api/routers/strategies.py | 2 ++ services/api/tests/test_api.py | 5 ++-- services/data-collector/src/data_collector/main.py | 4 ++- services/order-executor/src/order_executor/main.py | 4 ++- .../src/order_executor/risk_manager.py | 13 ++++++++-- .../src/portfolio_manager/main.py | 4 ++- .../strategy-engine/src/strategy_engine/main.py | 4 ++- .../strategies/combined_strategy.py | 3 ++- .../tests/test_combined_strategy.py | 29 +++++++++++++++------- 12 files changed, 54 insertions(+), 19 deletions(-) (limited to 'services') diff --git a/services/api/src/trading_api/main.py b/services/api/src/trading_api/main.py index 61cfe36..39f7b43 100644 --- a/services/api/src/trading_api/main.py +++ b/services/api/src/trading_api/main.py @@ -1,4 +1,5 @@ """Trading Platform REST API.""" + from contextlib import asynccontextmanager from fastapi import FastAPI diff --git a/services/api/src/trading_api/routers/orders.py b/services/api/src/trading_api/routers/orders.py index 989694f..d0b9fa6 100644 --- a/services/api/src/trading_api/routers/orders.py +++ b/services/api/src/trading_api/routers/orders.py @@ -1,4 +1,5 @@ """Order endpoints.""" + from fastapi import APIRouter, Request from shared.sa_models import OrderRow, SignalRow from sqlalchemy import select diff --git a/services/api/src/trading_api/routers/portfolio.py b/services/api/src/trading_api/routers/portfolio.py index f4169cb..3b30e1d 100644 --- a/services/api/src/trading_api/routers/portfolio.py +++ b/services/api/src/trading_api/routers/portfolio.py @@ -1,6 +1,7 @@ """Portfolio endpoints.""" + from fastapi import APIRouter, Request -from shared.sa_models import PositionRow, PortfolioSnapshotRow +from shared.sa_models import PositionRow from sqlalchemy import select router = APIRouter() diff --git a/services/api/src/trading_api/routers/strategies.py b/services/api/src/trading_api/routers/strategies.py index a8d778d..2861eec 100644 --- a/services/api/src/trading_api/routers/strategies.py +++ b/services/api/src/trading_api/routers/strategies.py @@ -1,4 +1,5 @@ """Strategy endpoints.""" + import sys from pathlib import Path @@ -16,6 +17,7 @@ router = APIRouter() async def list_strategies(): """List available strategies.""" from strategy_engine.plugin_loader import load_strategies + strategies_dir = _STRATEGY_DIR / "strategies" strategies = load_strategies(strategies_dir) return [ diff --git a/services/api/tests/test_api.py b/services/api/tests/test_api.py index 99cf9e3..669143b 100644 --- a/services/api/tests/test_api.py +++ b/services/api/tests/test_api.py @@ -1,12 +1,13 @@ """Tests for the REST API.""" -import pytest -from unittest.mock import AsyncMock, MagicMock, patch + +from unittest.mock import AsyncMock, patch from fastapi.testclient import TestClient def test_health_endpoint(): """Health endpoint returns ok.""" from trading_api.main import app + # Override lifespan to skip DB with patch("trading_api.main.lifespan") as mock_lifespan: mock_lifespan.return_value.__aenter__ = AsyncMock() diff --git a/services/data-collector/src/data_collector/main.py b/services/data-collector/src/data_collector/main.py index 81e13df..4384985 100644 --- a/services/data-collector/src/data_collector/main.py +++ b/services/data-collector/src/data_collector/main.py @@ -49,7 +49,9 @@ async def run() -> None: on_candle=on_candle, ) - health = HealthCheckServer("data-collector", port=config.health_port, auth_token=config.metrics_auth_token) + health = HealthCheckServer( + "data-collector", port=config.health_port, auth_token=config.metrics_auth_token + ) health.register_check("redis", broker.ping) await health.start() metrics.service_up.labels(service="data-collector").set(1) diff --git a/services/order-executor/src/order_executor/main.py b/services/order-executor/src/order_executor/main.py index 32470f6..1eeee7b 100644 --- a/services/order-executor/src/order_executor/main.py +++ b/services/order-executor/src/order_executor/main.py @@ -60,7 +60,9 @@ async def run() -> None: last_id = "$" stream = "signals" - health = HealthCheckServer("order-executor", port=config.health_port + 2, auth_token=config.metrics_auth_token) + health = HealthCheckServer( + "order-executor", port=config.health_port + 2, auth_token=config.metrics_auth_token + ) health.register_check("redis", broker.ping) await health.start() metrics.service_up.labels(service="order-executor").set(1) diff --git a/services/order-executor/src/order_executor/risk_manager.py b/services/order-executor/src/order_executor/risk_manager.py index 2b0a864..c3578a7 100644 --- a/services/order-executor/src/order_executor/risk_manager.py +++ b/services/order-executor/src/order_executor/risk_manager.py @@ -1,4 +1,5 @@ """Risk management for order execution.""" + from dataclasses import dataclass from decimal import Decimal from collections import deque @@ -16,6 +17,7 @@ class RiskCheckResult: @dataclass class TrailingStop: """Tracks trailing stop for a symbol.""" + symbol: str highest_price: Decimal stop_pct: Decimal # e.g. 5.0 for 5% @@ -86,7 +88,11 @@ class RiskManager: if not history or len(history) < 2: return None prices = list(history) - returns = [(prices[i] - prices[i-1]) / prices[i-1] for i in range(1, len(prices)) if prices[i-1] != 0] + returns = [ + (prices[i] - prices[i - 1]) / prices[i - 1] + for i in range(1, len(prices)) + if prices[i - 1] != 0 + ] if not returns: return None mean = sum(returns) / len(returns) @@ -153,7 +159,10 @@ class RiskManager: if position is not None: current_position_value = position.quantity * position.current_price - if balance > 0 and (current_position_value + order_cost) / balance > self.max_position_size: + if ( + balance > 0 + and (current_position_value + order_cost) / balance > self.max_position_size + ): return RiskCheckResult(allowed=False, reason="Position size exceeded") return RiskCheckResult(allowed=True, reason="OK") diff --git a/services/portfolio-manager/src/portfolio_manager/main.py b/services/portfolio-manager/src/portfolio_manager/main.py index be29a2f..d60e6c9 100644 --- a/services/portfolio-manager/src/portfolio_manager/main.py +++ b/services/portfolio-manager/src/portfolio_manager/main.py @@ -63,7 +63,9 @@ async def run() -> None: broker = RedisBroker(config.redis_url) tracker = PortfolioTracker() - health = HealthCheckServer("portfolio-manager", port=config.health_port + 3, auth_token=config.metrics_auth_token) + health = HealthCheckServer( + "portfolio-manager", port=config.health_port + 3, auth_token=config.metrics_auth_token + ) health.register_check("redis", broker.ping) await health.start() metrics.service_up.labels(service="portfolio-manager").set(1) diff --git a/services/strategy-engine/src/strategy_engine/main.py b/services/strategy-engine/src/strategy_engine/main.py index fabd755..9f3b3c9 100644 --- a/services/strategy-engine/src/strategy_engine/main.py +++ b/services/strategy-engine/src/strategy_engine/main.py @@ -43,7 +43,9 @@ async def run() -> None: engine = StrategyEngine(broker=broker, strategies=strategies) - health = HealthCheckServer("strategy-engine", port=config.health_port + 1, auth_token=config.metrics_auth_token) + health = HealthCheckServer( + "strategy-engine", port=config.health_port + 1, auth_token=config.metrics_auth_token + ) health.register_check("redis", broker.ping) await health.start() metrics.service_up.labels(service="strategy-engine").set(1) diff --git a/services/strategy-engine/strategies/combined_strategy.py b/services/strategy-engine/strategies/combined_strategy.py index e99dfdf..507ef5b 100644 --- a/services/strategy-engine/strategies/combined_strategy.py +++ b/services/strategy-engine/strategies/combined_strategy.py @@ -1,6 +1,6 @@ """Combined strategy that aggregates signals from multiple sub-strategies.""" + from decimal import Decimal -from typing import Optional from shared.models import Candle, Signal, OrderSide from strategies.base import BaseStrategy @@ -12,6 +12,7 @@ class CombinedStrategy(BaseStrategy): Each sub-strategy votes BUY (+weight), SELL (-weight), or HOLD (0). The combined signal fires when the weighted sum exceeds a threshold. """ + name: str = "combined" def __init__(self) -> None: diff --git a/services/strategy-engine/tests/test_combined_strategy.py b/services/strategy-engine/tests/test_combined_strategy.py index b860dca..3408a89 100644 --- a/services/strategy-engine/tests/test_combined_strategy.py +++ b/services/strategy-engine/tests/test_combined_strategy.py @@ -1,6 +1,8 @@ """Tests for Combined strategy.""" + import sys from pathlib import Path + sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from decimal import Decimal @@ -24,9 +26,12 @@ class AlwaysBuyStrategy(BaseStrategy): def on_candle(self, candle: Candle) -> Signal | None: return Signal( - strategy=self.name, symbol=candle.symbol, - side=OrderSide.BUY, price=candle.close, - quantity=Decimal("0.01"), reason="always buy", + strategy=self.name, + symbol=candle.symbol, + side=OrderSide.BUY, + price=candle.close, + quantity=Decimal("0.01"), + reason="always buy", ) @@ -42,9 +47,12 @@ class AlwaysSellStrategy(BaseStrategy): def on_candle(self, candle: Candle) -> Signal | None: return Signal( - strategy=self.name, symbol=candle.symbol, - side=OrderSide.SELL, price=candle.close, - quantity=Decimal("0.01"), reason="always sell", + strategy=self.name, + symbol=candle.symbol, + side=OrderSide.SELL, + price=candle.close, + quantity=Decimal("0.01"), + reason="always sell", ) @@ -64,10 +72,13 @@ class NeutralStrategy(BaseStrategy): def _candle(price=100.0): return Candle( - symbol="BTCUSDT", timeframe="1m", + symbol="BTCUSDT", + timeframe="1m", open_time=datetime(2025, 1, 1, tzinfo=timezone.utc), - open=Decimal(str(price)), high=Decimal(str(price+10)), - low=Decimal(str(price-10)), close=Decimal(str(price)), + open=Decimal(str(price)), + high=Decimal(str(price + 10)), + low=Decimal(str(price - 10)), + close=Decimal(str(price)), volume=Decimal("10"), ) -- cgit v1.2.3