diff --git a/backend/api/runtime.py b/backend/api/runtime.py
index a307fd7..24d3a9f 100644
--- a/backend/api/runtime.py
+++ b/backend/api/runtime.py
@@ -181,7 +181,6 @@ class LaunchConfig(BaseModel):
start_date: Optional[str] = Field(default=None, description="回测开始日期 YYYY-MM-DD")
end_date: Optional[str] = Field(default=None, description="回测结束日期 YYYY-MM-DD")
poll_interval: int = Field(default=10, ge=1, le=300, description="市场数据轮询间隔(秒)")
- enable_mock: bool = Field(default=False, description="是否启用模拟模式(使用模拟价格数据)")
class LaunchResponse(BaseModel):
@@ -756,7 +755,6 @@ async def start_runtime(
"start_date": config.start_date,
"end_date": config.end_date,
"poll_interval": config.poll_interval,
- "enable_mock": config.enable_mock,
}
retention_keep = max(1, int(os.getenv("RUNS_RETENTION_COUNT", "20") or "20"))
diff --git a/backend/cli.py b/backend/cli.py
index 3297448..6266bd5 100644
--- a/backend/cli.py
+++ b/backend/cli.py
@@ -1019,11 +1019,6 @@ def backtest(
@app.command()
def live(
- mock: bool = typer.Option(
- False,
- "--mock",
- help="Use mock mode with simulated prices (for testing)",
- ),
config_name: str = typer.Option(
"live",
"--config-name",
@@ -1078,7 +1073,6 @@ def live(
Example:
evotraders live # Run immediately (default)
- evotraders live --mock # Mock mode
evotraders live -t 22:30 # Run at 22:30 local time daily
evotraders live --schedule-mode intraday --interval-minutes 60
evotraders live --trigger-time now # Run immediately
@@ -1086,33 +1080,31 @@ def live(
"""
schedule_mode = str(_normalize_typer_value(schedule_mode, "daily"))
interval_minutes = int(_normalize_typer_value(interval_minutes, 60))
- mode_name = "MOCK" if mock else "LIVE"
console.print(
Panel.fit(
- f"[bold cyan]EvoTraders {mode_name} Mode[/bold cyan]",
+ "[bold cyan]EvoTraders LIVE Mode[/bold cyan]",
border_style="cyan",
),
)
# Check for required API key in live mode
- if not mock:
- env_file = get_project_root() / ".env"
- if not env_file.exists():
- console.print("\n[yellow]Warning: .env file not found[/yellow]")
- console.print("Creating from template...\n")
- template = get_project_root() / "env.template"
- if template.exists():
- shutil.copy(template, env_file)
- console.print("[green].env file created[/green]")
- console.print(
- "\n[red]Error: Please edit .env and set FINNHUB_API_KEY[/red]",
- )
- console.print(
- "Get your free API key at: https://finnhub.io/register\n",
- )
- else:
- console.print("[red]Error: env.template not found[/red]")
- raise typer.Exit(1)
+ env_file = get_project_root() / ".env"
+ if not env_file.exists():
+ console.print("\n[yellow]Warning: .env file not found[/yellow]")
+ console.print("Creating from template...\n")
+ template = get_project_root() / "env.template"
+ if template.exists():
+ shutil.copy(template, env_file)
+ console.print("[green].env file created[/green]")
+ console.print(
+ "\n[red]Error: Please edit .env and set FINNHUB_API_KEY[/red]",
+ )
+ console.print(
+ "Get your free API key at: https://finnhub.io/register\n",
+ )
+ else:
+ console.print("[red]Error: env.template not found[/red]")
+ raise typer.Exit(1)
# Handle historical data cleanup
handle_history_cleanup(config_name, auto_clean=clean)
@@ -1168,12 +1160,9 @@ def live(
# Display configuration
console.print("\n[bold]Configuration:[/bold]")
- if mock:
- console.print(" Mode: [yellow]MOCK[/yellow] (Simulated prices)")
- else:
- console.print(
- " Mode: [green]LIVE[/green] (Real-time prices via Finnhub)",
- )
+ console.print(
+ " Mode: [green]LIVE[/green] (Real-time prices via Finnhub)",
+ )
console.print(f" Config: {config_name}")
console.print(f" Server: {host}:{port}")
console.print(f" Poll Interval: {poll_interval}s")
@@ -1188,22 +1177,17 @@ def live(
project_root = get_project_root()
os.chdir(project_root)
- # Data update (if not mock mode)
- if not mock:
- run_data_updater(project_root)
- auto_update_market_store(
- config_name,
- end_date=nyse_now.date().isoformat(),
- )
- auto_enrich_market_store(
- config_name,
- end_date=nyse_now.date().isoformat(),
- force=False,
- )
- else:
- console.print(
- "\n[dim]Mock mode enabled - skipping data update[/dim]\n",
- )
+ # Data update
+ run_data_updater(project_root)
+ auto_update_market_store(
+ config_name,
+ end_date=nyse_now.date().isoformat(),
+ )
+ auto_enrich_market_store(
+ config_name,
+ end_date=nyse_now.date().isoformat(),
+ force=False,
+ )
# Build command using backend.main
cmd = [
@@ -1229,8 +1213,6 @@ def live(
str(interval_minutes),
]
- if mock:
- cmd.append("--mock")
if enable_memory:
cmd.append("--enable-memory")
diff --git a/backend/core/pipeline_runner.py b/backend/core/pipeline_runner.py
index c875fa6..5b68db7 100644
--- a/backend/core/pipeline_runner.py
+++ b/backend/core/pipeline_runner.py
@@ -244,10 +244,8 @@ async def run_pipeline(
start_date = bootstrap.get("start_date")
end_date = bootstrap.get("end_date")
enable_memory = bootstrap.get("enable_memory", False)
- enable_mock = bootstrap.get("enable_mock", False)
is_backtest = mode == "backtest"
- is_mock = enable_mock or mode == "mock" or (not is_backtest and os.getenv("MOCK_MODE", "false").lower() == "true")
# ======================================================================
# PHASE 0: Initialize runtime manager
@@ -288,9 +286,8 @@ async def run_pipeline(
market_service = MarketService(
tickers=tickers,
poll_interval=10,
- mock_mode=is_mock and not is_backtest,
backtest_mode=is_backtest,
- api_key=os.getenv("FINNHUB_API_KEY") if not is_mock and not is_backtest else None,
+ api_key=os.getenv("FINNHUB_API_KEY") if not is_backtest else None,
backtest_start_date=start_date if is_backtest else None,
backtest_end_date=end_date if is_backtest else None,
)
@@ -387,7 +384,6 @@ async def run_pipeline(
scheduler_callback=scheduler_callback,
config={
"mode": mode,
- "mock_mode": is_mock,
"backtest_mode": is_backtest,
"tickers": tickers,
"config_name": run_id,
diff --git a/backend/core/state_sync.py b/backend/core/state_sync.py
index 304e835..4404d52 100644
--- a/backend/core/state_sync.py
+++ b/backend/core/state_sync.py
@@ -465,7 +465,6 @@ class StateSync:
payload = {
"server_mode": self._state.get("server_mode", "live"),
- "is_mock_mode": self._state.get("is_mock_mode", False),
"is_backtest": self._state.get("is_backtest", False),
"tickers": self._state.get("tickers"),
"runtime_config": self._state.get("runtime_config"),
diff --git a/backend/data/__init__.py b/backend/data/__init__.py
index eb90e8e..5eb3cff 100644
--- a/backend/data/__init__.py
+++ b/backend/data/__init__.py
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from backend.data.historical_price_manager import HistoricalPriceManager
-from backend.data.mock_price_manager import MockPriceManager
from backend.data.polling_price_manager import PollingPriceManager
-__all__ = ["MockPriceManager", "PollingPriceManager", "HistoricalPriceManager"]
+__all__ = ["PollingPriceManager", "HistoricalPriceManager"]
diff --git a/backend/data/mock_price_manager.py b/backend/data/mock_price_manager.py
deleted file mode 100644
index cf92935..0000000
--- a/backend/data/mock_price_manager.py
+++ /dev/null
@@ -1,244 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Mock Price Manager - For testing during non-trading hours
-Generates virtual real-time price data
-"""
-import logging
-import os
-import random
-import threading
-import time
-from typing import Callable, Dict, List, Optional
-from backend.data.provider_utils import normalize_symbol
-
-logger = logging.getLogger(__name__)
-
-
-class MockPriceManager:
- """Mock Price Manager - Generates virtual prices for testing"""
-
- def __init__(self, poll_interval: int = 10, volatility: float = 0.5):
- """
- Args:
- poll_interval: Price update interval in seconds
- volatility: Price volatility percentage
- """
- if poll_interval is None:
- poll_interval = int(os.getenv("MOCK_POLL_INTERVAL", "5"))
- if volatility is None:
- volatility = float(os.getenv("MOCK_VOLATILITY", "0.5"))
-
- self.poll_interval = poll_interval
- self.volatility = volatility
-
- self.subscribed_symbols: List[str] = []
- self.base_prices: Dict[str, float] = {}
- self.open_prices: Dict[str, float] = {}
- self.latest_prices: Dict[str, float] = {}
- self.price_callbacks: List[Callable] = []
-
- self.running = False
- self._thread: Optional[threading.Thread] = None
-
- self.default_base_prices = {
- "AAPL": 237.50,
- "MSFT": 425.30,
- "GOOGL": 161.50,
- "AMZN": 218.45,
- "NVDA": 950.00,
- "META": 573.22,
- "TSLA": 342.15,
- "AMD": 168.90,
- "NFLX": 688.25,
- "INTC": 42.18,
- "COIN": 285.50,
- "PLTR": 45.80,
- "BABA": 88.30,
- "DIS": 112.50,
- "BKNG": 4850.00,
- }
-
- logger.info(
- f"MockPriceManager initialized (interval: {self.poll_interval}s, "
- f"volatility: {self.volatility}%)",
- )
-
- def subscribe(
- self,
- symbols: List[str],
- base_prices: Dict[str, float] = None,
- ):
- """Subscribe to stock symbols"""
- for symbol in symbols:
- symbol = normalize_symbol(symbol)
- if symbol not in self.subscribed_symbols:
- self.subscribed_symbols.append(symbol)
-
- if base_prices and symbol in base_prices:
- base_price = base_prices[symbol]
- elif symbol in self.default_base_prices:
- base_price = self.default_base_prices[symbol]
- else:
- base_price = random.uniform(50, 500)
-
- self.base_prices[symbol] = base_price
- self.open_prices[symbol] = base_price
- self.latest_prices[symbol] = base_price
-
- logger.info(
- f"Subscribed to mock price: {symbol} (base: ${base_price:.2f})", # noqa: E501
- )
-
- def unsubscribe(self, symbols: List[str]):
- """Unsubscribe from symbols"""
- for symbol in symbols:
- symbol = normalize_symbol(symbol)
- if symbol in self.subscribed_symbols:
- self.subscribed_symbols.remove(symbol)
- self.base_prices.pop(symbol, None)
- self.open_prices.pop(symbol, None)
- self.latest_prices.pop(symbol, None)
- logger.info(f"Unsubscribed: {symbol}")
-
- def add_price_callback(self, callback: Callable):
- """Add price update callback"""
- self.price_callbacks.append(callback)
-
- def _generate_price_update(self, symbol: str) -> float:
- """Generate price update based on random walk"""
- current_price = self.latest_prices.get(
- symbol,
- self.base_prices[symbol],
- )
-
- change_percent = random.uniform(-self.volatility, self.volatility)
- new_price = current_price * (1 + change_percent / 100)
-
- # 10% chance of larger movement
- if random.random() < 0.1:
- trend_factor = random.uniform(-2, 2)
- new_price = new_price * (1 + trend_factor / 100)
-
- # Limit intraday movement to +/-10%
- open_price = self.open_prices[symbol]
- max_price = open_price * 1.10
- min_price = open_price * 0.90
- new_price = max(min_price, min(max_price, new_price))
-
- return new_price
-
- def _update_prices(self):
- """Update prices for all subscribed stocks"""
- timestamp = int(time.time() * 1000)
-
- for symbol in self.subscribed_symbols:
- try:
- new_price = self._generate_price_update(symbol)
- self.latest_prices[symbol] = new_price
-
- open_price = self.open_prices[symbol]
- ret = ((new_price - open_price) / open_price) * 100
-
- price_data = {
- "symbol": symbol,
- "price": new_price,
- "timestamp": timestamp,
- "volume": random.randint(1000000, 10000000),
- "open": open_price,
- "high": max(new_price, open_price),
- "low": min(new_price, open_price),
- "previous_close": open_price,
- "ret": ret,
- }
-
- for callback in self.price_callbacks:
- try:
- callback(price_data)
- except Exception as e:
- logger.error(
- f"Mock price callback error ({symbol}): {e}",
- )
-
- logger.debug(
- f"Mock {symbol}: ${new_price:.2f} [ret: {ret:+.2f}%]",
- )
-
- except Exception as e:
- logger.error(f"Failed to generate mock price ({symbol}): {e}")
-
- def _polling_loop(self):
- """Main polling loop"""
- logger.info(
- f"Mock price generation started (interval: {self.poll_interval}s)",
- )
-
- while self.running:
- try:
- start_time = time.time()
- self._update_prices()
-
- elapsed = time.time() - start_time
- sleep_time = max(0, self.poll_interval - elapsed)
- if sleep_time > 0:
- time.sleep(sleep_time)
-
- except Exception as e:
- logger.error(f"Mock polling loop error: {e}")
- time.sleep(5)
-
- def start(self):
- """Start mock price generation"""
- if self.running:
- logger.warning("Mock price manager already running")
- return
-
- if not self.subscribed_symbols:
- logger.warning("No stocks subscribed")
- return
-
- self.running = True
- self._thread = threading.Thread(target=self._polling_loop, daemon=True)
- self._thread.start()
-
- logger.info(
- f"Mock price manager started: {', '.join(self.subscribed_symbols)}", # noqa: E501
- )
-
- def stop(self):
- """Stop mock price generation"""
- self.running = False
- if self._thread:
- self._thread.join(timeout=5)
- logger.info("Mock price manager stopped")
-
- def get_latest_price(self, symbol: str) -> Optional[float]:
- """Get latest price for symbol"""
- return self.latest_prices.get(symbol)
-
- def get_all_latest_prices(self) -> Dict[str, float]:
- """Get all latest prices"""
- return self.latest_prices.copy()
-
- def get_open_price(self, symbol: str) -> Optional[float]:
- """Get open price for symbol"""
- return self.open_prices.get(symbol)
-
- def reset_open_prices(self):
- """Reset open prices for new trading day"""
- for symbol in self.subscribed_symbols:
- last_close = self.latest_prices[symbol]
- gap_percent = random.uniform(-1, 1)
- new_open = last_close * (1 + gap_percent / 100)
- self.open_prices[symbol] = new_open
- self.latest_prices[symbol] = new_open
- logger.info("Open prices reset")
-
- def set_base_price(self, symbol: str, price: float):
- """Manually set base price for testing"""
- if symbol in self.subscribed_symbols:
- self.base_prices[symbol] = price
- self.open_prices[symbol] = price
- self.latest_prices[symbol] = price
- logger.info(f"{symbol} base price set to: ${price:.2f}")
- else:
- logger.warning(f"{symbol} not subscribed")
diff --git a/backend/gateway_server.py b/backend/gateway_server.py
index 60cb019..cd9b5eb 100644
--- a/backend/gateway_server.py
+++ b/backend/gateway_server.py
@@ -130,10 +130,8 @@ async def run_gateway(
end_date = bootstrap.get("end_date")
enable_memory = bootstrap.get("enable_memory", False)
poll_interval = int(bootstrap.get("poll_interval", 10))
- enable_mock = bootstrap.get("enable_mock", False)
is_backtest = mode == "backtest"
- is_mock = enable_mock or mode == "mock" or (not is_backtest and os.getenv("MOCK_MODE", "false").lower() == "true")
logger.info(f"[Gateway Server] Starting run {run_id} on port {port}")
@@ -152,9 +150,8 @@ async def run_gateway(
market_service = MarketService(
tickers=tickers,
poll_interval=poll_interval,
- mock_mode=is_mock and not is_backtest,
backtest_mode=is_backtest,
- api_key=os.getenv("FINNHUB_API_KEY") if not is_mock and not is_backtest else None,
+ api_key=os.getenv("FINNHUB_API_KEY") if not is_backtest else None,
backtest_start_date=start_date if is_backtest else None,
backtest_end_date=end_date if is_backtest else None,
)
@@ -247,7 +244,6 @@ async def run_gateway(
scheduler_callback=scheduler_callback,
config={
"mode": mode,
- "mock_mode": is_mock,
"backtest_mode": is_backtest,
"tickers": tickers,
"config_name": run_id,
diff --git a/backend/main.py b/backend/main.py
index f5c75e5..b1356a8 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
Main Entry Point
-Supports: backtest, live, mock modes
+Supports: backtest, live modes
"""
import argparse
import asyncio
@@ -231,11 +231,8 @@ async def run_with_gateway(args):
market_service = MarketService(
tickers=tickers,
poll_interval=args.poll_interval,
- mock_mode=args.mock and not is_backtest,
backtest_mode=is_backtest,
- api_key=os.getenv("FINNHUB_API_KEY")
- if not args.mock and not is_backtest
- else None,
+ api_key=os.getenv("FINNHUB_API_KEY") if not is_backtest else None,
backtest_start_date=args.start_date if is_backtest else None,
backtest_end_date=args.end_date if is_backtest else None,
)
@@ -320,7 +317,6 @@ async def run_with_gateway(args):
scheduler_callback=scheduler_callback,
config={
"mode": args.mode,
- "mock_mode": args.mock,
"backtest_mode": is_backtest,
"tickers": tickers,
"config_name": config_name,
@@ -353,8 +349,7 @@ def main():
"""Main entry point"""
parser = argparse.ArgumentParser(description="Trading System")
parser.add_argument("--mode", choices=["live", "backtest"], default="live")
- parser.add_argument("--mock", action="store_true")
- parser.add_argument("--config-name", default="mock")
+ parser.add_argument("--config-name", default="live")
parser.add_argument("--host", default="0.0.0.0")
parser.add_argument("--port", type=int, default=8765)
parser.add_argument(
diff --git a/backend/services/gateway.py b/backend/services/gateway.py
index 7c7252d..894f1d9 100644
--- a/backend/services/gateway.py
+++ b/backend/services/gateway.py
@@ -111,7 +111,6 @@ class Gateway:
host=host,
port=port,
poll_interval=self.config.get("poll_interval", 10),
- mock=self.config.get("mock_mode", False),
tickers=self.config.get("tickers", []),
initial_cash=self.storage.initial_cash,
start_date=self._backtest_start_date or "",
@@ -125,10 +124,6 @@ class Gateway:
self.state_sync.update_state("status", "initializing")
self.state_sync.update_state("server_mode", self.mode)
self.state_sync.update_state("is_backtest", self.is_backtest)
- self.state_sync.update_state(
- "is_mock_mode",
- self.config.get("mock_mode", False),
- )
self.state_sync.update_state("tickers", self.config.get("tickers", []))
self.state_sync.update_state(
"runtime_config",
@@ -545,13 +540,13 @@ class Gateway:
websocket: ServerConnection,
data: Dict[str, Any],
) -> None:
- """Run one live/mock trading cycle on demand."""
+ """Run one live trading cycle on demand."""
if self.is_backtest:
await websocket.send(
json.dumps(
{
"type": "error",
- "message": "Manual trigger is only available in live/mock mode.",
+ "message": "Manual trigger is only available in live mode.",
},
ensure_ascii=False,
),
diff --git a/backend/services/market.py b/backend/services/market.py
index 2749f76..557fce9 100644
--- a/backend/services/market.py
+++ b/backend/services/market.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
Market Data Service
-Supports live, mock, and backtest modes
+Supports live and backtest modes
"""
import asyncio
import logging
@@ -36,7 +36,6 @@ class MarketService:
self,
tickers: List[str],
poll_interval: int = 10,
- mock_mode: bool = False,
backtest_mode: bool = False,
api_key: Optional[str] = None,
backtest_start_date: Optional[str] = None,
@@ -44,7 +43,6 @@ class MarketService:
):
self.tickers = [normalize_symbol(ticker) for ticker in tickers]
self.poll_interval = poll_interval
- self.mock_mode = mock_mode
self.backtest_mode = backtest_mode
self.api_key = api_key
self.backtest_start_date = backtest_start_date
@@ -69,8 +67,6 @@ class MarketService:
"""Return the active live quote provider for UI/debugging."""
if self.backtest_mode:
return "backtest"
- if self.mock_mode:
- return "mock"
if self._price_manager and hasattr(self._price_manager, "provider"):
provider = getattr(self._price_manager, "provider", None)
if isinstance(provider, str) and provider.strip():
@@ -81,8 +77,6 @@ class MarketService:
def mode_name(self) -> str:
if self.backtest_mode:
return "BACKTEST"
- elif self.mock_mode:
- return "MOCK"
return "LIVE"
async def start(self, broadcast_func: Callable):
@@ -96,8 +90,6 @@ class MarketService:
if self.backtest_mode:
self._start_backtest_mode()
- elif self.mock_mode:
- self._start_mock_mode()
else:
self._start_real_mode()
@@ -125,20 +117,6 @@ class MarketService:
return callback
- def _start_mock_mode(self):
- from backend.data.mock_price_manager import MockPriceManager
-
- self._price_manager = MockPriceManager(
- poll_interval=self.poll_interval,
- volatility=0.5,
- )
- self._price_manager.add_price_callback(self._make_price_callback())
- self._price_manager.subscribe(
- self.tickers,
- base_prices={t: 100.0 for t in self.tickers},
- )
- self._price_manager.start()
-
def _start_real_mode(self):
from backend.data.polling_price_manager import PollingPriceManager
@@ -262,13 +240,7 @@ class MarketService:
if removed:
self._price_manager.unsubscribe(removed)
if added:
- if self.mock_mode:
- self._price_manager.subscribe(
- added,
- base_prices={ticker: 100.0 for ticker in added},
- )
- else:
- self._price_manager.subscribe(added)
+ self._price_manager.subscribe(added)
if self.backtest_mode and self._current_date:
self._price_manager.set_date(self._current_date)
diff --git a/backend/tests/test_cli.py b/backend/tests/test_cli.py
index 986be98..92f68e2 100644
--- a/backend/tests/test_cli.py
+++ b/backend/tests/test_cli.py
@@ -34,7 +34,6 @@ def test_live_runs_incremental_market_store_update_before_start(monkeypatch, tmp
monkeypatch.setattr(cli.subprocess, "run", fake_run)
cli.live(
- mock=False,
config_name="smoke_fullstack",
host="0.0.0.0",
port=8765,
diff --git a/backend/tests/test_market_service.py b/backend/tests/test_market_service.py
index e376f54..35289de 100644
--- a/backend/tests/test_market_service.py
+++ b/backend/tests/test_market_service.py
@@ -6,153 +6,10 @@ import logging
from unittest.mock import MagicMock, AsyncMock, patch
import pytest
from backend.services.market import MarketService
-from backend.data.mock_price_manager import MockPriceManager
from backend.data.polling_price_manager import PollingPriceManager
from backend.llm.models import RetryChatModel
-class TestMockPriceManager:
- def test_init_default(self):
- manager = MockPriceManager()
-
- assert manager.poll_interval == 10
- assert manager.volatility == 0.5
- assert manager.running is False
- assert len(manager.subscribed_symbols) == 0
-
- def test_init_custom(self):
- manager = MockPriceManager(poll_interval=5, volatility=1.0)
-
- assert manager.poll_interval == 5
- assert manager.volatility == 1.0
-
- def test_subscribe(self):
- manager = MockPriceManager()
- manager.subscribe(["AAPL", "MSFT"])
-
- assert "AAPL" in manager.subscribed_symbols
- assert "MSFT" in manager.subscribed_symbols
- assert manager.base_prices["AAPL"] == 237.50 # default price
- assert manager.base_prices["MSFT"] == 425.30 # default price
-
- def test_subscribe_with_base_prices(self):
- manager = MockPriceManager()
- manager.subscribe(["AAPL"], base_prices={"AAPL": 100.0})
-
- assert manager.base_prices["AAPL"] == 100.0
- assert manager.open_prices["AAPL"] == 100.0
- assert manager.latest_prices["AAPL"] == 100.0
-
- def test_subscribe_unknown_symbol(self):
- manager = MockPriceManager()
- manager.subscribe(["UNKNOWN"])
-
- assert "UNKNOWN" in manager.subscribed_symbols
- assert manager.base_prices["UNKNOWN"] > 0 # random price generated
-
- def test_unsubscribe(self):
- manager = MockPriceManager()
- manager.subscribe(["AAPL", "MSFT"])
- manager.unsubscribe(["AAPL"])
-
- assert "AAPL" not in manager.subscribed_symbols
- assert "MSFT" in manager.subscribed_symbols
-
- def test_add_price_callback(self):
- manager = MockPriceManager()
- callback = MagicMock()
- manager.add_price_callback(callback)
-
- assert callback in manager.price_callbacks
-
- def test_generate_price_update_within_bounds(self):
- manager = MockPriceManager(volatility=0.5)
- manager.subscribe(["AAPL"], base_prices={"AAPL": 100.0})
-
- for _ in range(100):
- new_price = manager._generate_price_update("AAPL")
- # Should be within +/-10% of open
- assert 90.0 <= new_price <= 110.0
-
- def test_update_prices_triggers_callback(self):
- manager = MockPriceManager()
- manager.subscribe(["AAPL"], base_prices={"AAPL": 100.0})
-
- callback = MagicMock()
- manager.add_price_callback(callback)
-
- manager._update_prices()
-
- callback.assert_called_once()
- call_args = callback.call_args[0][0]
- assert call_args["symbol"] == "AAPL"
- assert "price" in call_args
- assert "timestamp" in call_args
-
- def test_start_stop(self):
- manager = MockPriceManager(poll_interval=1)
- manager.subscribe(["AAPL"], base_prices={"AAPL": 100.0})
-
- manager.start()
- assert manager.running is True
-
- time.sleep(0.1) # let thread start
-
- manager.stop()
- assert manager.running is False
-
- def test_start_without_subscription(self):
- manager = MockPriceManager()
- manager.start()
-
- assert (
- manager.running is False
- ) # should not start without subscriptions
-
- def test_get_latest_price(self):
- manager = MockPriceManager()
- manager.subscribe(["AAPL"], base_prices={"AAPL": 100.0})
-
- price = manager.get_latest_price("AAPL")
- assert price == 100.0
-
- def test_get_latest_price_unknown(self):
- manager = MockPriceManager()
- price = manager.get_latest_price("UNKNOWN")
- assert price is None
-
- def test_get_all_latest_prices(self):
- manager = MockPriceManager()
- manager.subscribe(
- ["AAPL", "MSFT"],
- base_prices={"AAPL": 100.0, "MSFT": 200.0},
- )
-
- prices = manager.get_all_latest_prices()
- assert prices["AAPL"] == 100.0
- assert prices["MSFT"] == 200.0
-
- def test_reset_open_prices(self):
- manager = MockPriceManager()
- manager.subscribe(["AAPL"], base_prices={"AAPL": 100.0})
- manager.latest_prices["AAPL"] = 105.0
-
- manager.reset_open_prices()
-
- # Open price should change (based on latest with small gap)
- assert manager.open_prices["AAPL"] != 100.0
-
- def test_set_base_price(self):
- manager = MockPriceManager()
- manager.subscribe(["AAPL"], base_prices={"AAPL": 100.0})
-
- manager.set_base_price("AAPL", 150.0)
-
- assert manager.base_prices["AAPL"] == 150.0
- assert manager.open_prices["AAPL"] == 150.0
- assert manager.latest_prices["AAPL"] == 150.0
-
-
class TestPollingPriceManager:
def test_init(self):
manager = PollingPriceManager(api_key="test_key", poll_interval=30)
@@ -288,35 +145,12 @@ class TestRetryChatModel:
class TestMarketService:
- def test_init_mock_mode(self):
- service = MarketService(
- tickers=["AAPL", "MSFT"],
- poll_interval=10,
- mock_mode=True,
- )
-
- assert service.tickers == ["AAPL", "MSFT"]
- assert service.poll_interval == 10
- assert service.mock_mode is True
- assert service.running is False
-
- def test_init_real_mode(self):
- service = MarketService(
- tickers=["AAPL"],
- mock_mode=False,
- api_key="test_key",
- )
-
- assert service.mock_mode is False
- assert service.api_key == "test_key"
-
@patch("backend.services.market.get_data_sources", return_value=["yfinance", "local_csv"])
@patch.object(PollingPriceManager, "start")
def test_start_real_mode_with_yfinance(self, _mock_start, _mock_sources):
service = MarketService(
tickers=["AAPL"],
poll_interval=10,
- mock_mode=False,
)
service._start_real_mode()
@@ -330,7 +164,6 @@ class TestMarketService:
service = MarketService(
tickers=["AAPL"],
poll_interval=10,
- mock_mode=False,
)
service._start_real_mode()
@@ -338,30 +171,11 @@ class TestMarketService:
assert isinstance(service._price_manager, PollingPriceManager)
assert service._price_manager.provider == "yfinance"
- @pytest.mark.asyncio
- async def test_start_mock_mode(self):
- service = MarketService(
- tickers=["AAPL"],
- poll_interval=10,
- mock_mode=True,
- )
-
- broadcast_func = AsyncMock()
-
- await service.start(broadcast_func)
-
- assert service.running is True
- assert service._price_manager is not None
- assert isinstance(service._price_manager, MockPriceManager)
-
- service.stop()
-
@patch("backend.services.market.get_data_sources", return_value=["finnhub", "yfinance"])
@pytest.mark.asyncio
async def test_start_real_mode_without_api_key(self, _mock_sources):
service = MarketService(
tickers=["AAPL"],
- mock_mode=False,
api_key=None,
)
@@ -376,11 +190,12 @@ class TestMarketService:
async def test_start_already_running(self):
service = MarketService(
tickers=["AAPL"],
- mock_mode=True,
+ backtest_mode=True,
)
broadcast_func = AsyncMock()
+ # First start with backtest mode
await service.start(broadcast_func)
assert service.running is True
@@ -392,7 +207,7 @@ class TestMarketService:
def test_stop(self):
service = MarketService(
tickers=["AAPL"],
- mock_mode=True,
+ backtest_mode=True,
)
service.running = True
service._price_manager = MagicMock()
@@ -405,7 +220,7 @@ class TestMarketService:
def test_stop_when_not_running(self):
service = MarketService(
tickers=["AAPL"],
- mock_mode=True,
+ backtest_mode=True,
)
# Should not raise
@@ -413,20 +228,20 @@ class TestMarketService:
assert service.running is False
def test_get_price_sync(self):
- service = MarketService(tickers=["AAPL"], mock_mode=True)
+ service = MarketService(tickers=["AAPL"], backtest_mode=True)
service.cache["AAPL"] = {"price": 150.0, "open": 148.0}
price = service.get_price_sync("AAPL")
assert price == 150.0
def test_get_price_sync_not_found(self):
- service = MarketService(tickers=["AAPL"], mock_mode=True)
+ service = MarketService(tickers=["AAPL"], backtest_mode=True)
price = service.get_price_sync("MSFT")
assert price is None
def test_get_all_prices(self):
- service = MarketService(tickers=["AAPL", "MSFT"], mock_mode=True)
+ service = MarketService(tickers=["AAPL", "MSFT"], backtest_mode=True)
service.cache["AAPL"] = {"price": 150.0}
service.cache["MSFT"] = {"price": 400.0}
@@ -437,7 +252,7 @@ class TestMarketService:
@pytest.mark.asyncio
async def test_broadcast_price_update(self):
- service = MarketService(tickers=["AAPL"], mock_mode=True)
+ service = MarketService(tickers=["AAPL"], backtest_mode=True)
service._broadcast_func = AsyncMock()
price_data = {
@@ -457,7 +272,7 @@ class TestMarketService:
@pytest.mark.asyncio
async def test_broadcast_price_update_no_func(self):
- service = MarketService(tickers=["AAPL"], mock_mode=True)
+ service = MarketService(tickers=["AAPL"], backtest_mode=True)
service._broadcast_func = None
price_data = {"symbol": "AAPL", "price": 150.0, "open": 148.0}
@@ -465,67 +280,6 @@ class TestMarketService:
# Should not raise
await service._broadcast_price_update(price_data)
- @pytest.mark.asyncio
- async def test_price_callback_thread_safety(self):
- service = MarketService(
- tickers=["AAPL"],
- poll_interval=1,
- mock_mode=True,
- )
-
- received_prices = []
-
- async def capture_broadcast(msg):
- received_prices.append(msg)
-
- await service.start(capture_broadcast)
-
- # Wait for at least one price update
- await asyncio.sleep(1.5)
-
- service.stop()
-
- # Should have received at least one price update
- assert len(received_prices) >= 1
- assert received_prices[0]["type"] == "price_update"
-
-
-class TestMarketServiceIntegration:
- @pytest.mark.asyncio
- async def test_full_mock_cycle(self):
- service = MarketService(
- tickers=["AAPL", "MSFT"],
- poll_interval=1,
- mock_mode=True,
- )
-
- messages = []
-
- async def collect_messages(msg):
- messages.append(msg)
-
- await service.start(collect_messages)
-
- # Wait for price updates
- await asyncio.sleep(2.5)
-
- service.stop()
-
- # Should have received multiple price updates
- assert len(messages) >= 2
-
- # Check message structure
- symbols_seen = set()
- for msg in messages:
- assert msg["type"] == "price_update"
- assert "symbol" in msg
- assert "price" in msg
- assert "ret" in msg
- symbols_seen.add(msg["symbol"])
-
- # Should have prices for both tickers
- assert "AAPL" in symbols_seen or "MSFT" in symbols_seen
-
if __name__ == "__main__":
pytest.main([__file__, "-v"])
diff --git a/backend/tests/test_runtime_service_app.py b/backend/tests/test_runtime_service_app.py
index 8801e1e..e464261 100644
--- a/backend/tests/test_runtime_service_app.py
+++ b/backend/tests/test_runtime_service_app.py
@@ -310,7 +310,6 @@ def test_start_runtime_restore_reuses_historical_run_id(monkeypatch, tmp_path):
"enable_memory": False,
"mode": "live",
"poll_interval": 10,
- "enable_mock": False,
},
}
}
diff --git a/backend/utils/terminal_dashboard.py b/backend/utils/terminal_dashboard.py
index 1a79e1a..9656954 100644
--- a/backend/utils/terminal_dashboard.py
+++ b/backend/utils/terminal_dashboard.py
@@ -30,7 +30,6 @@ class TerminalDashboard:
self.port = 8765
self.poll_interval = 10
self.trigger_time = "now"
- self.mock = False
self.enable_memory = False
self.local_time = ""
self.nyse_time = ""
@@ -65,7 +64,6 @@ class TerminalDashboard:
port: int,
poll_interval: int,
trigger_time: str = "now",
- mock: bool = False,
enable_memory: bool = False,
local_time: str = "",
nyse_time: str = "",
@@ -82,7 +80,6 @@ class TerminalDashboard:
self.port = port
self.poll_interval = poll_interval
self.trigger_time = trigger_time
- self.mock = mock
self.enable_memory = enable_memory
self.local_time = local_time
self.nyse_time = nyse_time
@@ -109,8 +106,6 @@ class TerminalDashboard:
# Mode line
if self.mode == "backtest":
mode_str = "[cyan]Backtest[/cyan]"
- elif self.mock:
- mode_str = "[yellow]MOCK[/yellow]"
else:
mode_str = "[green]LIVE[/green]"
@@ -216,8 +211,6 @@ class TerminalDashboard:
title = "[bold cyan]EvoTraders[/bold cyan]"
if self.mode == "backtest":
title += " [dim]Backtest[/dim]"
- elif self.mock:
- title += " [dim]Mock[/dim]"
else:
title += " [dim]Live[/dim]"
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index a4ce83f..cfa7717 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -291,7 +291,6 @@ export default function LiveTradingApp() {
financial_datasets: 'FINANCIAL DATASETS',
local_csv: 'CSV',
polygon: 'POLYGON',
- mock: 'MOCK',
backtest: 'BACKTEST',
}), []);
@@ -415,7 +414,6 @@ export default function LiveTradingApp() {
pollIntervalDraft={runtimeControls.pollIntervalDraft}
startDateDraft={runtimeControls.startDateDraft}
endDateDraft={runtimeControls.endDateDraft}
- enableMockDraft={runtimeControls.enableMockDraft}
watchlistDraftSymbols={runtimeControls.watchlistDraftSymbols}
watchlistInputValue={runtimeControls.watchlistInputValue}
watchlistSuggestions={runtimeControls.watchlistSuggestions}
@@ -432,7 +430,6 @@ export default function LiveTradingApp() {
onPollIntervalChange={runtimeControls.setPollIntervalDraft}
onStartDateChange={runtimeControls.setStartDateDraft}
onEndDateChange={runtimeControls.setEndDateDraft}
- onEnableMockChange={runtimeControls.setEnableMockDraft}
onWatchlistInputChange={runtimeControls.handleWatchlistInputChange}
onWatchlistInputKeyDown={runtimeControls.handleWatchlistInputKeyDown}
onWatchlistAdd={runtimeControls.handleWatchlistAdd}
diff --git a/frontend/src/components/AppShell.jsx b/frontend/src/components/AppShell.jsx
index 86eca78..cd7b399 100644
--- a/frontend/src/components/AppShell.jsx
+++ b/frontend/src/components/AppShell.jsx
@@ -72,7 +72,6 @@ export default function AppShell({
pollIntervalDraft,
startDateDraft,
endDateDraft,
- enableMockDraft,
watchlistDraftSymbols,
watchlistInputValue,
watchlistSuggestions,
@@ -89,7 +88,6 @@ export default function AppShell({
onPollIntervalChange,
onStartDateChange,
onEndDateChange,
- onEnableMockChange,
onWatchlistInputChange,
onWatchlistInputKeyDown,
onWatchlistAdd,
@@ -186,44 +184,6 @@ export default function AppShell({