summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/src/trading_cli/main.py2
-rw-r--r--pyproject.toml2
-rwxr-xr-xscripts/backtest_moc.py246
-rw-r--r--services/api/tests/test_portfolio_router.py4
-rw-r--r--services/backtester/src/backtester/config.py2
-rw-r--r--services/backtester/tests/test_walk_forward.py2
-rw-r--r--services/data-collector/tests/test_storage.py6
-rw-r--r--services/order-executor/tests/test_risk_manager.py46
-rw-r--r--services/portfolio-manager/tests/test_portfolio.py24
-rw-r--r--services/portfolio-manager/tests/test_snapshot.py2
-rw-r--r--services/strategy-engine/src/strategy_engine/config.py2
-rw-r--r--shared/tests/test_broker.py6
-rw-r--r--shared/tests/test_notifier.py12
13 files changed, 301 insertions, 55 deletions
diff --git a/cli/src/trading_cli/main.py b/cli/src/trading_cli/main.py
index db3c282..1129bdd 100644
--- a/cli/src/trading_cli/main.py
+++ b/cli/src/trading_cli/main.py
@@ -10,7 +10,7 @@ from trading_cli.commands.service import service
@click.group()
@click.version_option(version="0.1.0")
def cli():
- """Trading Platform CLI — Binance spot crypto trading"""
+ """Trading Platform CLI — US stock trading"""
pass
diff --git a/pyproject.toml b/pyproject.toml
index 545eae1..6938778 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[project]
name = "trading-platform"
version = "0.1.0"
-description = "Binance spot crypto trading platform"
+description = "US stock trading platform"
requires-python = ">=3.12"
[tool.pytest.ini_options]
diff --git a/scripts/backtest_moc.py b/scripts/backtest_moc.py
new file mode 100755
index 0000000..92b426b
--- /dev/null
+++ b/scripts/backtest_moc.py
@@ -0,0 +1,246 @@
+#!/usr/bin/env python3
+"""Backtest and optimize MOC strategy on synthetic US stock data.
+
+Usage: python scripts/backtest_moc.py
+"""
+
+import sys
+import random
+from pathlib import Path
+from decimal import Decimal
+from datetime import datetime, timedelta, timezone
+
+ROOT = Path(__file__).resolve().parents[1]
+sys.path.insert(0, str(ROOT / "services" / "strategy-engine" / "src"))
+sys.path.insert(0, str(ROOT / "services" / "strategy-engine"))
+sys.path.insert(0, str(ROOT / "services" / "backtester" / "src"))
+sys.path.insert(0, str(ROOT / "shared" / "src"))
+
+from shared.models import Candle # noqa: E402
+from backtester.engine import BacktestEngine # noqa: E402
+from strategies.moc_strategy import MocStrategy # noqa: E402
+
+
+def generate_stock_candles(
+ symbol: str = "AAPL",
+ days: int = 90,
+ base_price: float = 180.0,
+ daily_drift: float = 0.0003, # Slight upward bias
+ daily_vol: float = 0.015, # 1.5% daily vol
+) -> list[Candle]:
+ """Generate realistic US stock intraday candles (5-min bars).
+
+ Simulates:
+ - Market hours only (14:30-21:00 UTC = 9:30-16:00 ET)
+ - Opening gaps (overnight news effect)
+ - Intraday volatility pattern (higher at open/close)
+ - Volume pattern (U-shaped: high at open, low midday, high at close)
+ """
+ candles = []
+ price = base_price
+ start_date = datetime(2025, 1, 2, tzinfo=timezone.utc) # Start on a Thursday
+
+ trading_day = 0
+ current_date = start_date
+
+ while trading_day < days:
+ # Skip weekends
+ if current_date.weekday() >= 5:
+ current_date += timedelta(days=1)
+ continue
+
+ # Opening gap: overnight news effect
+ gap_pct = random.gauss(daily_drift, daily_vol * 0.5) # Gap is ~50% of daily vol
+ price *= 1 + gap_pct
+
+ # Generate 78 5-minute bars (9:30-16:00 = 6.5 hours = 78 bars)
+ intraday_bars = 78
+ for bar in range(intraday_bars):
+ # Time: 14:30 UTC + bar * 5 minutes
+ dt = current_date.replace(hour=14, minute=30) + timedelta(minutes=bar * 5)
+
+ # Intraday volatility pattern (U-shaped)
+ hour_of_day = bar / intraday_bars
+ if hour_of_day < 0.1: # First 10% of day (opening)
+ vol = daily_vol * 0.003
+ elif hour_of_day > 0.9: # Last 10% (closing)
+ vol = daily_vol * 0.0025
+ else: # Middle of day
+ vol = daily_vol * 0.001
+
+ # Add daily trend component
+ intraday_drift = daily_drift / intraday_bars
+ change = random.gauss(intraday_drift, vol)
+
+ open_p = price
+ close_p = price * (1 + change)
+ high_p = max(open_p, close_p) * (1 + abs(random.gauss(0, vol * 0.3)))
+ low_p = min(open_p, close_p) * (1 - abs(random.gauss(0, vol * 0.3)))
+
+ # Volume pattern (U-shaped)
+ if hour_of_day < 0.1 or hour_of_day > 0.85:
+ volume = random.uniform(500000, 2000000)
+ else:
+ volume = random.uniform(100000, 500000)
+
+ candles.append(
+ Candle(
+ symbol=symbol,
+ timeframe="5Min",
+ open_time=dt,
+ open=Decimal(str(round(open_p, 2))),
+ high=Decimal(str(round(high_p, 2))),
+ low=Decimal(str(round(low_p, 2))),
+ close=Decimal(str(round(close_p, 2))),
+ volume=Decimal(str(int(volume))),
+ )
+ )
+
+ price = close_p
+
+ trading_day += 1
+ current_date += timedelta(days=1)
+
+ return candles
+
+
+def run_backtest(candles, params, balance=750.0):
+ """Run a single backtest."""
+ strategy = MocStrategy()
+ strategy.configure(params)
+
+ engine = BacktestEngine(
+ strategy=strategy,
+ initial_balance=Decimal(str(balance)),
+ slippage_pct=0.0005, # 0.05% slippage (stocks have tighter spreads)
+ taker_fee_pct=0.0, # Alpaca = 0% commission
+ )
+ return engine.run(candles)
+
+
+def main():
+ random.seed(42)
+
+ print("=" * 60)
+ print("MOC Strategy Backtest — US Stocks")
+ print("Capital: $750 (~100만원)")
+ print("=" * 60)
+
+ # Test across multiple stocks
+ stocks = [
+ ("AAPL", 180.0, 0.0003, 0.015),
+ ("MSFT", 420.0, 0.0004, 0.014),
+ ("TSLA", 250.0, 0.0001, 0.030),
+ ("NVDA", 800.0, 0.0005, 0.025),
+ ("AMZN", 185.0, 0.0003, 0.018),
+ ]
+
+ # Parameter grid
+ param_sets = []
+ for rsi_min in [25, 30, 35]:
+ for rsi_max in [55, 60, 65]:
+ for sl in [1.5, 2.0, 3.0]:
+ for ema in [10, 20]:
+ param_sets.append(
+ {
+ "quantity_pct": 0.2,
+ "stop_loss_pct": sl,
+ "rsi_min": rsi_min,
+ "rsi_max": rsi_max,
+ "ema_period": ema,
+ "volume_avg_period": 20,
+ "min_volume_ratio": 0.8,
+ "buy_start_utc": 19,
+ "buy_end_utc": 21,
+ "sell_start_utc": 14,
+ "sell_end_utc": 15,
+ "max_positions": 5,
+ }
+ )
+
+ print(f"\nParameter combinations: {len(param_sets)}")
+ print(f"Stocks: {[s[0] for s in stocks]}")
+ print("Generating 90 days of 5-min data per stock...\n")
+
+ # Generate data for each stock
+ all_candles = {}
+ for symbol, base, drift, vol in stocks:
+ all_candles[symbol] = generate_stock_candles(
+ symbol, days=90, base_price=base, daily_drift=drift, daily_vol=vol
+ )
+ print(f" {symbol}: {len(all_candles[symbol])} candles")
+
+ # Test each parameter set across all stocks
+ print(
+ f"\nRunning {len(param_sets)} x {len(stocks)} = {len(param_sets) * len(stocks)} backtests..."
+ )
+
+ param_results = []
+ for i, params in enumerate(param_sets):
+ total_profit = Decimal("0")
+ total_trades = 0
+ total_sharpe = 0.0
+ stock_details = []
+
+ for symbol, _, _, _ in stocks:
+ result = run_backtest(all_candles[symbol], params)
+ total_profit += result.profit
+ total_trades += result.total_trades
+ if result.detailed:
+ total_sharpe += result.detailed.sharpe_ratio
+ stock_details.append((symbol, result))
+
+ avg_sharpe = total_sharpe / len(stocks) if stocks else 0
+ param_results.append((params, total_profit, total_trades, avg_sharpe, stock_details))
+
+ if (i + 1) % 18 == 0:
+ print(f" Progress: {i + 1}/{len(param_sets)}")
+
+ # Sort by average Sharpe
+ param_results.sort(key=lambda x: x[3], reverse=True)
+
+ print("\n" + "=" * 60)
+ print("TOP 5 PARAMETER SETS (by avg Sharpe across all stocks)")
+ print("=" * 60)
+
+ for rank, (params, profit, trades, sharpe, details) in enumerate(param_results[:5], 1):
+ print(f"\n#{rank}:")
+ print(
+ f" RSI: {params['rsi_min']}-{params['rsi_max']},"
+ f" SL: {params['stop_loss_pct']}%, EMA: {params['ema_period']}"
+ )
+ print(f" Total Profit: ${float(profit):.2f}, Trades: {trades}, Avg Sharpe: {sharpe:.3f}")
+ print(" Per stock:")
+ for symbol, result in details:
+ pct = float(result.profit_pct)
+ dd = result.detailed.max_drawdown if result.detailed else 0
+ print(f" {symbol}: {pct:+.2f}% ({result.total_trades} trades, DD: {dd:.1f}%)")
+
+ # Best params
+ best = param_results[0]
+ print("\n" + "=" * 60)
+ print("RECOMMENDED PARAMETERS")
+ print("=" * 60)
+ bp = best[0]
+ print(f" rsi_min: {bp['rsi_min']}")
+ print(f" rsi_max: {bp['rsi_max']}")
+ print(f" stop_loss_pct: {bp['stop_loss_pct']}")
+ print(f" ema_period: {bp['ema_period']}")
+ print(f" min_volume_ratio: {bp['min_volume_ratio']}")
+ print(f"\n Avg Sharpe: {best[3]:.3f}")
+ print(f" Total Profit: ${float(best[1]):.2f} across 5 stocks over 90 days")
+
+ # Worst for comparison
+ print("\n" + "=" * 60)
+ print("WORST 3 PARAMETER SETS")
+ print("=" * 60)
+ for _rank, (params, profit, trades, sharpe, _) in enumerate(param_results[-3:], 1):
+ print(
+ f" RSI({params['rsi_min']}-{params['rsi_max']}),"
+ f" SL={params['stop_loss_pct']}%, EMA={params['ema_period']}"
+ )
+ print(f" Profit: ${float(profit):.2f}, Sharpe: {sharpe:.3f}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/services/api/tests/test_portfolio_router.py b/services/api/tests/test_portfolio_router.py
index f2584ea..3bd1b2c 100644
--- a/services/api/tests/test_portfolio_router.py
+++ b/services/api/tests/test_portfolio_router.py
@@ -45,7 +45,7 @@ def test_get_positions_with_data(app, mock_db):
app.state.db = db
mock_row = MagicMock()
- mock_row.symbol = "BTCUSDT"
+ mock_row.symbol = "AAPL"
mock_row.quantity = Decimal("0.1")
mock_row.avg_entry_price = Decimal("50000")
mock_row.current_price = Decimal("55000")
@@ -59,7 +59,7 @@ def test_get_positions_with_data(app, mock_db):
assert response.status_code == 200
data = response.json()
assert len(data) == 1
- assert data[0]["symbol"] == "BTCUSDT"
+ assert data[0]["symbol"] == "AAPL"
def test_get_snapshots_empty(app, mock_db):
diff --git a/services/backtester/src/backtester/config.py b/services/backtester/src/backtester/config.py
index f7897da..57ee1fb 100644
--- a/services/backtester/src/backtester/config.py
+++ b/services/backtester/src/backtester/config.py
@@ -5,7 +5,7 @@ from shared.config import Settings
class BacktestConfig(Settings):
backtest_initial_balance: float = 10000.0
- symbol: str = "BTCUSDT"
+ symbol: str = "AAPL"
timeframe: str = "1h"
strategy_name: str = "rsi_strategy"
candle_limit: int = 500
diff --git a/services/backtester/tests/test_walk_forward.py b/services/backtester/tests/test_walk_forward.py
index 5ab2e7b..96abb6e 100644
--- a/services/backtester/tests/test_walk_forward.py
+++ b/services/backtester/tests/test_walk_forward.py
@@ -21,7 +21,7 @@ def _generate_candles(n=100, base_price=100.0):
price = base_price + (i % 20) - 10
candles.append(
Candle(
- symbol="BTCUSDT",
+ symbol="AAPL",
timeframe="1h",
open_time=datetime(2025, 1, 1, tzinfo=timezone.utc) + timedelta(hours=i),
open=Decimal(str(price)),
diff --git a/services/data-collector/tests/test_storage.py b/services/data-collector/tests/test_storage.py
index be85578..ffffa40 100644
--- a/services/data-collector/tests/test_storage.py
+++ b/services/data-collector/tests/test_storage.py
@@ -9,7 +9,7 @@ from shared.models import Candle
from data_collector.storage import CandleStorage
-def _make_candle(symbol: str = "BTCUSDT") -> Candle:
+def _make_candle(symbol: str = "AAPL") -> Candle:
return Candle(
symbol=symbol,
timeframe="1m",
@@ -39,11 +39,11 @@ async def test_storage_saves_to_db_and_publishes():
mock_broker.publish.assert_called_once()
stream_arg = mock_broker.publish.call_args[0][0]
- assert stream_arg == "candles.BTCUSDT"
+ assert stream_arg == "candles.AAPL"
data_arg = mock_broker.publish.call_args[0][1]
assert data_arg["type"] == "CANDLE"
- assert data_arg["data"]["symbol"] == "BTCUSDT"
+ assert data_arg["data"]["symbol"] == "AAPL"
@pytest.mark.asyncio
diff --git a/services/order-executor/tests/test_risk_manager.py b/services/order-executor/tests/test_risk_manager.py
index 00a9ab4..3d5175b 100644
--- a/services/order-executor/tests/test_risk_manager.py
+++ b/services/order-executor/tests/test_risk_manager.py
@@ -7,7 +7,7 @@ from shared.models import OrderSide, Position, Signal
from order_executor.risk_manager import RiskManager
-def make_signal(side: OrderSide, price: str, quantity: str, symbol: str = "BTC/USDT") -> Signal:
+def make_signal(side: OrderSide, price: str, quantity: str, symbol: str = "AAPL") -> Signal:
return Signal(
strategy="test",
symbol=symbol,
@@ -93,7 +93,7 @@ def test_risk_check_rejects_insufficient_balance():
def test_trailing_stop_set_and_trigger():
"""Trailing stop should trigger when price drops below stop level."""
rm = make_risk_manager(trailing_stop_pct="5")
- rm.set_trailing_stop("BTC/USDT", Decimal("100"))
+ rm.set_trailing_stop("AAPL", Decimal("100"))
signal = make_signal(side=OrderSide.BUY, price="94", quantity="0.01")
result = rm.check(signal, balance=Decimal("10000"), positions={}, daily_pnl=Decimal("0"))
@@ -104,10 +104,10 @@ def test_trailing_stop_set_and_trigger():
def test_trailing_stop_updates_highest_price():
"""Trailing stop should track the highest price seen."""
rm = make_risk_manager(trailing_stop_pct="5")
- rm.set_trailing_stop("BTC/USDT", Decimal("100"))
+ rm.set_trailing_stop("AAPL", Decimal("100"))
# Price rises to 120 => stop at 114
- rm.update_price("BTC/USDT", Decimal("120"))
+ rm.update_price("AAPL", Decimal("120"))
# Price at 115 is above stop (114), should be allowed
signal = make_signal(side=OrderSide.BUY, price="115", quantity="0.01")
@@ -124,7 +124,7 @@ def test_trailing_stop_updates_highest_price():
def test_trailing_stop_not_triggered_above_stop():
"""Trailing stop should not trigger when price is above stop level."""
rm = make_risk_manager(trailing_stop_pct="5")
- rm.set_trailing_stop("BTC/USDT", Decimal("100"))
+ rm.set_trailing_stop("AAPL", Decimal("100"))
# Price at 96 is above stop (95), should be allowed
signal = make_signal(side=OrderSide.BUY, price="96", quantity="0.01")
@@ -140,11 +140,11 @@ def test_max_open_positions_check():
rm = make_risk_manager(max_open_positions=2)
positions = {
- "BTC/USDT": make_position("BTC/USDT", "1", "100", "100"),
- "ETH/USDT": make_position("ETH/USDT", "10", "50", "50"),
+ "AAPL": make_position("AAPL", "1", "100", "100"),
+ "MSFT": make_position("MSFT", "10", "50", "50"),
}
- signal = make_signal(side=OrderSide.BUY, price="10", quantity="1", symbol="SOL/USDT")
+ signal = make_signal(side=OrderSide.BUY, price="10", quantity="1", symbol="TSLA")
result = rm.check(signal, balance=Decimal("10000"), positions=positions, daily_pnl=Decimal("0"))
assert result.allowed is False
assert result.reason == "Max open positions reached"
@@ -158,14 +158,14 @@ def test_volatility_calculation():
rm = make_risk_manager(volatility_lookback=5)
# No history yet
- assert rm.get_volatility("BTC/USDT") is None
+ assert rm.get_volatility("AAPL") is None
# Feed prices
prices = [100, 102, 98, 105, 101]
for p in prices:
- rm.update_price("BTC/USDT", Decimal(str(p)))
+ rm.update_price("AAPL", Decimal(str(p)))
- vol = rm.get_volatility("BTC/USDT")
+ vol = rm.get_volatility("AAPL")
assert vol is not None
assert vol > 0
@@ -177,9 +177,9 @@ def test_position_size_with_volatility_scaling():
# Feed volatile prices
prices = [100, 120, 80, 130, 70]
for p in prices:
- rm.update_price("BTC/USDT", Decimal(str(p)))
+ rm.update_price("AAPL", Decimal(str(p)))
- size = rm.calculate_position_size("BTC/USDT", Decimal("10000"))
+ size = rm.calculate_position_size("AAPL", Decimal("10000"))
base = Decimal("10000") * Decimal("0.1")
# High volatility should reduce size below base
@@ -192,9 +192,9 @@ def test_position_size_without_scaling():
prices = [100, 120, 80, 130, 70]
for p in prices:
- rm.update_price("BTC/USDT", Decimal(str(p)))
+ rm.update_price("AAPL", Decimal(str(p)))
- size = rm.calculate_position_size("BTC/USDT", Decimal("10000"))
+ size = rm.calculate_position_size("AAPL", Decimal("10000"))
base = Decimal("10000") * Decimal("0.1")
assert size == base
@@ -211,8 +211,8 @@ def test_portfolio_exposure_check_passes():
max_portfolio_exposure=0.8,
)
positions = {
- "BTCUSDT": Position(
- symbol="BTCUSDT",
+ "AAPL": Position(
+ symbol="AAPL",
quantity=Decimal("0.01"),
avg_entry_price=Decimal("50000"),
current_price=Decimal("50000"),
@@ -230,8 +230,8 @@ def test_portfolio_exposure_check_rejects():
max_portfolio_exposure=0.3,
)
positions = {
- "BTCUSDT": Position(
- symbol="BTCUSDT",
+ "AAPL": Position(
+ symbol="AAPL",
quantity=Decimal("1"),
avg_entry_price=Decimal("50000"),
current_price=Decimal("50000"),
@@ -263,10 +263,10 @@ def test_var_calculation():
daily_loss_limit_pct=Decimal("10"),
)
for i in range(30):
- rm.update_price("BTCUSDT", Decimal(str(100 + (i % 5) - 2)))
+ rm.update_price("AAPL", Decimal(str(100 + (i % 5) - 2)))
positions = {
- "BTCUSDT": Position(
- symbol="BTCUSDT",
+ "AAPL": Position(
+ symbol="AAPL",
quantity=Decimal("1"),
avg_entry_price=Decimal("100"),
current_price=Decimal("100"),
@@ -357,7 +357,7 @@ def test_drawdown_check_rejects_in_check():
rm.update_balance(Decimal("10000"))
signal = Signal(
strategy="test",
- symbol="BTC/USDT",
+ symbol="AAPL",
side=OrderSide.BUY,
price=Decimal("50000"),
quantity=Decimal("0.01"),
diff --git a/services/portfolio-manager/tests/test_portfolio.py b/services/portfolio-manager/tests/test_portfolio.py
index 768e071..365dc1a 100644
--- a/services/portfolio-manager/tests/test_portfolio.py
+++ b/services/portfolio-manager/tests/test_portfolio.py
@@ -10,7 +10,7 @@ def make_order(side: OrderSide, price: str, quantity: str) -> Order:
"""Helper to create a filled Order."""
return Order(
signal_id="test-signal",
- symbol="BTC/USDT",
+ symbol="AAPL",
side=side,
type=OrderType.MARKET,
price=Decimal(price),
@@ -24,7 +24,7 @@ def test_portfolio_add_buy_order() -> None:
order = make_order(OrderSide.BUY, "50000", "0.1")
tracker.apply_order(order)
- position = tracker.get_position("BTC/USDT")
+ position = tracker.get_position("AAPL")
assert position is not None
assert position.quantity == Decimal("0.1")
assert position.avg_entry_price == Decimal("50000")
@@ -35,7 +35,7 @@ def test_portfolio_add_multiple_buys() -> None:
tracker.apply_order(make_order(OrderSide.BUY, "50000", "0.1"))
tracker.apply_order(make_order(OrderSide.BUY, "52000", "0.1"))
- position = tracker.get_position("BTC/USDT")
+ position = tracker.get_position("AAPL")
assert position is not None
assert position.quantity == Decimal("0.2")
assert position.avg_entry_price == Decimal("51000")
@@ -46,7 +46,7 @@ def test_portfolio_sell_reduces_position() -> None:
tracker.apply_order(make_order(OrderSide.BUY, "50000", "0.2"))
tracker.apply_order(make_order(OrderSide.SELL, "55000", "0.1"))
- position = tracker.get_position("BTC/USDT")
+ position = tracker.get_position("AAPL")
assert position is not None
assert position.quantity == Decimal("0.1")
assert position.avg_entry_price == Decimal("50000")
@@ -54,7 +54,7 @@ def test_portfolio_sell_reduces_position() -> None:
def test_portfolio_no_position_returns_none() -> None:
tracker = PortfolioTracker()
- position = tracker.get_position("ETH/USDT")
+ position = tracker.get_position("MSFT")
assert position is None
@@ -66,7 +66,7 @@ def test_realized_pnl_on_sell() -> None:
tracker.apply_order(
Order(
signal_id="s1",
- symbol="BTCUSDT",
+ symbol="AAPL",
side=OrderSide.BUY,
type=OrderType.MARKET,
price=Decimal("50000"),
@@ -80,7 +80,7 @@ def test_realized_pnl_on_sell() -> None:
tracker.apply_order(
Order(
signal_id="s2",
- symbol="BTCUSDT",
+ symbol="AAPL",
side=OrderSide.SELL,
type=OrderType.MARKET,
price=Decimal("55000"),
@@ -98,7 +98,7 @@ def test_realized_pnl_on_loss() -> None:
tracker.apply_order(
Order(
signal_id="s1",
- symbol="BTCUSDT",
+ symbol="AAPL",
side=OrderSide.BUY,
type=OrderType.MARKET,
price=Decimal("50000"),
@@ -109,7 +109,7 @@ def test_realized_pnl_on_loss() -> None:
tracker.apply_order(
Order(
signal_id="s2",
- symbol="BTCUSDT",
+ symbol="AAPL",
side=OrderSide.SELL,
type=OrderType.MARKET,
price=Decimal("45000"),
@@ -128,7 +128,7 @@ def test_realized_pnl_accumulates() -> None:
tracker.apply_order(
Order(
signal_id="s1",
- symbol="BTCUSDT",
+ symbol="AAPL",
side=OrderSide.BUY,
type=OrderType.MARKET,
price=Decimal("50000"),
@@ -141,7 +141,7 @@ def test_realized_pnl_accumulates() -> None:
tracker.apply_order(
Order(
signal_id="s2",
- symbol="BTCUSDT",
+ symbol="AAPL",
side=OrderSide.SELL,
type=OrderType.MARKET,
price=Decimal("55000"),
@@ -154,7 +154,7 @@ def test_realized_pnl_accumulates() -> None:
tracker.apply_order(
Order(
signal_id="s3",
- symbol="BTCUSDT",
+ symbol="AAPL",
side=OrderSide.SELL,
type=OrderType.MARKET,
price=Decimal("60000"),
diff --git a/services/portfolio-manager/tests/test_snapshot.py b/services/portfolio-manager/tests/test_snapshot.py
index a464599..ec5e92d 100644
--- a/services/portfolio-manager/tests/test_snapshot.py
+++ b/services/portfolio-manager/tests/test_snapshot.py
@@ -13,7 +13,7 @@ class TestSaveSnapshot:
from portfolio_manager.main import save_snapshot
pos = Position(
- symbol="BTCUSDT",
+ symbol="AAPL",
quantity=Decimal("0.5"),
avg_entry_price=Decimal("50000"),
current_price=Decimal("52000"),
diff --git a/services/strategy-engine/src/strategy_engine/config.py b/services/strategy-engine/src/strategy_engine/config.py
index e3a49c2..9fd9c49 100644
--- a/services/strategy-engine/src/strategy_engine/config.py
+++ b/services/strategy-engine/src/strategy_engine/config.py
@@ -4,6 +4,6 @@ from shared.config import Settings
class StrategyConfig(Settings):
- symbols: list[str] = ["BTC/USDT"]
+ symbols: list[str] = ["AAPL", "MSFT", "GOOGL", "AMZN", "TSLA"]
timeframes: list[str] = ["1m"]
strategy_params: dict = {}
diff --git a/shared/tests/test_broker.py b/shared/tests/test_broker.py
index 9be84b0..eb1582d 100644
--- a/shared/tests/test_broker.py
+++ b/shared/tests/test_broker.py
@@ -16,7 +16,7 @@ async def test_broker_publish():
from shared.broker import RedisBroker
broker = RedisBroker("redis://localhost:6379")
- data = {"type": "CANDLE", "symbol": "BTCUSDT"}
+ data = {"type": "CANDLE", "symbol": "AAPL"}
await broker.publish("candles", data)
mock_redis.xadd.assert_called_once()
@@ -35,7 +35,7 @@ async def test_broker_subscribe_returns_messages():
mock_redis = AsyncMock()
mock_from_url.return_value = mock_redis
- payload_data = {"type": "CANDLE", "symbol": "ETHUSDT"}
+ payload_data = {"type": "CANDLE", "symbol": "MSFT"}
mock_redis.xread.return_value = [
[
b"candles",
@@ -53,7 +53,7 @@ async def test_broker_subscribe_returns_messages():
mock_redis.xread.assert_called_once()
assert len(messages) == 1
assert messages[0]["type"] == "CANDLE"
- assert messages[0]["symbol"] == "ETHUSDT"
+ assert messages[0]["symbol"] == "MSFT"
@pytest.mark.asyncio
diff --git a/shared/tests/test_notifier.py b/shared/tests/test_notifier.py
index 3d29830..6c81369 100644
--- a/shared/tests/test_notifier.py
+++ b/shared/tests/test_notifier.py
@@ -86,7 +86,7 @@ class TestTelegramNotifierFormatters:
notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
signal = Signal(
strategy="rsi_strategy",
- symbol="BTCUSDT",
+ symbol="AAPL",
side=OrderSide.BUY,
price=Decimal("50000.00"),
quantity=Decimal("0.01"),
@@ -99,7 +99,7 @@ class TestTelegramNotifierFormatters:
msg = mock_send.call_args[0][0]
assert "BUY" in msg
assert "rsi_strategy" in msg
- assert "BTCUSDT" in msg
+ assert "AAPL" in msg
assert "50000.00" in msg
assert "0.01" in msg
assert "RSI oversold" in msg
@@ -109,7 +109,7 @@ class TestTelegramNotifierFormatters:
notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
order = Order(
signal_id=str(uuid.uuid4()),
- symbol="ETHUSDT",
+ symbol="MSFT",
side=OrderSide.SELL,
type=OrderType.LIMIT,
price=Decimal("3000.50"),
@@ -122,7 +122,7 @@ class TestTelegramNotifierFormatters:
mock_send.assert_called_once()
msg = mock_send.call_args[0][0]
assert "FILLED" in msg
- assert "ETHUSDT" in msg
+ assert "MSFT" in msg
assert "SELL" in msg
assert "3000.50" in msg
assert "1.5" in msg
@@ -143,7 +143,7 @@ class TestTelegramNotifierFormatters:
notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
positions = [
Position(
- symbol="BTCUSDT",
+ symbol="AAPL",
quantity=Decimal("0.1"),
avg_entry_price=Decimal("50000"),
current_price=Decimal("51000"),
@@ -158,7 +158,7 @@ class TestTelegramNotifierFormatters:
)
mock_send.assert_called_once()
msg = mock_send.call_args[0][0]
- assert "BTCUSDT" in msg
+ assert "AAPL" in msg
assert "5100.00" in msg
assert "100.00" in msg