summaryrefslogtreecommitdiff
path: root/services/order-executor
diff options
context:
space:
mode:
Diffstat (limited to 'services/order-executor')
-rw-r--r--services/order-executor/src/order_executor/config.py1
-rw-r--r--services/order-executor/src/order_executor/executor.py21
-rw-r--r--services/order-executor/src/order_executor/main.py17
-rw-r--r--services/order-executor/src/order_executor/risk_manager.py6
-rw-r--r--services/order-executor/tests/test_executor.py1
-rw-r--r--services/order-executor/tests/test_risk_manager.py8
6 files changed, 38 insertions, 16 deletions
diff --git a/services/order-executor/src/order_executor/config.py b/services/order-executor/src/order_executor/config.py
index 856045f..6542a31 100644
--- a/services/order-executor/src/order_executor/config.py
+++ b/services/order-executor/src/order_executor/config.py
@@ -1,4 +1,5 @@
"""Order Executor configuration."""
+
from shared.config import Settings
diff --git a/services/order-executor/src/order_executor/executor.py b/services/order-executor/src/order_executor/executor.py
index 099520d..80f441d 100644
--- a/services/order-executor/src/order_executor/executor.py
+++ b/services/order-executor/src/order_executor/executor.py
@@ -1,4 +1,5 @@
"""Order execution logic."""
+
import structlog
from datetime import datetime, timezone
from decimal import Decimal
@@ -7,7 +8,7 @@ from typing import Any, Optional
from shared.broker import RedisBroker
from shared.db import Database
from shared.events import OrderEvent
-from shared.models import Order, OrderSide, OrderStatus, OrderType, Signal
+from shared.models import Order, OrderStatus, OrderType, Signal
from shared.notifier import TelegramNotifier
from order_executor.risk_manager import RiskManager
@@ -58,9 +59,7 @@ class OrderExecutor:
)
if not result.allowed:
- logger.warning(
- "risk_check_rejected", signal_id=str(signal.id), reason=result.reason
- )
+ logger.warning("risk_check_rejected", signal_id=str(signal.id), reason=result.reason)
return None
# Build the order model
@@ -77,7 +76,12 @@ class OrderExecutor:
if self.dry_run:
order.status = OrderStatus.FILLED
order.filled_at = datetime.now(timezone.utc)
- logger.info("order_filled_dry_run", side=str(order.side), quantity=str(order.quantity), symbol=order.symbol)
+ logger.info(
+ "order_filled_dry_run",
+ side=str(order.side),
+ quantity=str(order.quantity),
+ symbol=order.symbol,
+ )
else:
try:
await self.exchange.create_order(
@@ -88,7 +92,12 @@ class OrderExecutor:
)
order.status = OrderStatus.FILLED
order.filled_at = datetime.now(timezone.utc)
- logger.info("order_filled", side=str(order.side), quantity=str(order.quantity), symbol=order.symbol)
+ logger.info(
+ "order_filled",
+ side=str(order.side),
+ quantity=str(order.quantity),
+ symbol=order.symbol,
+ )
except Exception as exc:
order.status = OrderStatus.FAILED
logger.error("order_failed", signal_id=str(signal.id), error=str(exc))
diff --git a/services/order-executor/src/order_executor/main.py b/services/order-executor/src/order_executor/main.py
index 7f0578d..ab6ef4f 100644
--- a/services/order-executor/src/order_executor/main.py
+++ b/services/order-executor/src/order_executor/main.py
@@ -1,4 +1,5 @@
"""Order Executor Service entry point."""
+
import asyncio
from decimal import Decimal
@@ -21,7 +22,9 @@ async def run() -> None:
config = ExecutorConfig()
log = setup_logging("order-executor", config.log_level, config.log_format)
metrics = ServiceMetrics("order_executor")
- notifier = TelegramNotifier(bot_token=config.telegram_bot_token, chat_id=config.telegram_chat_id)
+ notifier = TelegramNotifier(
+ bot_token=config.telegram_bot_token, chat_id=config.telegram_chat_id
+ )
db = Database(config.database_url)
await db.connect()
@@ -69,12 +72,18 @@ async def run() -> None:
event = Event.from_dict(msg)
if event.type == EventType.SIGNAL:
signal = event.data
- log.info("processing_signal", signal_id=str(signal.id), symbol=signal.symbol)
+ log.info(
+ "processing_signal", signal_id=str(signal.id), symbol=signal.symbol
+ )
await executor.execute(signal)
- metrics.events_processed.labels(service="order-executor", event_type="signal").inc()
+ metrics.events_processed.labels(
+ service="order-executor", event_type="signal"
+ ).inc()
except Exception as exc:
log.error("message_processing_failed", error=str(exc))
- metrics.errors_total.labels(service="order-executor", error_type="processing").inc()
+ metrics.errors_total.labels(
+ service="order-executor", error_type="processing"
+ ).inc()
if messages:
# Advance last_id to avoid re-reading — broker.read returns decoded dicts,
# so we track progress by re-reading with "0" for replaying or "$" for new only.
diff --git a/services/order-executor/src/order_executor/risk_manager.py b/services/order-executor/src/order_executor/risk_manager.py
index 8e8a72c..db162e1 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
@@ -49,7 +50,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/order-executor/tests/test_executor.py b/services/order-executor/tests/test_executor.py
index 4836ffb..e64b6c0 100644
--- a/services/order-executor/tests/test_executor.py
+++ b/services/order-executor/tests/test_executor.py
@@ -1,4 +1,5 @@
"""Tests for OrderExecutor."""
+
from decimal import Decimal
from unittest.mock import AsyncMock, MagicMock
diff --git a/services/order-executor/tests/test_risk_manager.py b/services/order-executor/tests/test_risk_manager.py
index f6b5545..a122d16 100644
--- a/services/order-executor/tests/test_risk_manager.py
+++ b/services/order-executor/tests/test_risk_manager.py
@@ -1,9 +1,9 @@
"""Tests for RiskManager."""
+
from decimal import Decimal
-import pytest
-from shared.models import OrderSide, Position, Signal
+from shared.models import OrderSide, Signal
from order_executor.risk_manager import RiskManager
@@ -55,9 +55,7 @@ def test_risk_check_rejects_daily_loss_exceeded():
"""Daily PnL of -1100 on 10000 balance = -11%, exceeding -10% limit."""
rm = make_risk_manager(daily_loss_limit_pct="10.0")
signal = make_signal(side=OrderSide.BUY, price="100", quantity="0.1")
- result = rm.check(
- signal, balance=Decimal("10000"), positions={}, daily_pnl=Decimal("-1100")
- )
+ result = rm.check(signal, balance=Decimal("10000"), positions={}, daily_pnl=Decimal("-1100"))
assert result.allowed is False
assert result.reason == "Daily loss limit exceeded"