Add Docker support and fix benchmark/data pipeline bugs

Containerize the application with ROCm GPU support for AMD Radeon R9700:
- Add Dockerfile with PyTorch/PyG ROCm 5.6 wheels
- Add docker-compose.yml with dashboard, live-trading, and train services
- Add .dockerignore and .env.example for configuration

Fix benchmark script to use batch_size instead of num_stocks for variable
dimensions, and replace fragile partial model surgery with a standalone MLP
for memory estimation.

Fix data pipeline to skip dates with no next trading date instead of
fabricating zero returns.

Add slippage to paper broker, optional mark-to-market prices to broker
interface, and health check endpoint for container orchestration.
This commit is contained in:
2026-05-26 15:07:28 +02:00
parent bc40a67180
commit 46657c7ffe
12 changed files with 471 additions and 40 deletions
+29 -9
View File
@@ -673,8 +673,8 @@ class StockDataPipeline:
"""Return the next date that has price data for at least one ticker."""
candidate = date + timedelta(days=1)
for _ in range(7):
for ticker in self.price_data.values():
if not ticker.empty and candidate in ticker.index:
for price_df in self.price_data.values():
if not price_df.empty and candidate in price_df.index:
return candidate
candidate += timedelta(days=1)
return None
@@ -742,13 +742,19 @@ class StockDataPipeline:
# Build graph edges
edge_index, edge_weight = self._build_edges(node_tickers, date, pit_cache)
# Build targets: next trading day's return for each stock
# Build targets: next trading day's return for each stock.
# Skip dates where no next trading date exists (e.g. tail end of dataset)
# to avoid polluting training labels with fabricated zero returns.
next_date = self._next_trading_date(date)
if next_date is None:
continue
y_vals: List[float] = []
for ticker in node_tickers:
valid_seqs_for_y: List[np.ndarray] = []
valid_tickers_for_y: List[str] = []
for i, ticker in enumerate(node_tickers):
if (
next_date is not None
and ticker in self.price_data
ticker in self.price_data
and next_date in self.price_data[ticker].index
and date in self.price_data[ticker].index
):
@@ -757,9 +763,23 @@ class StockDataPipeline:
/ self.price_data[ticker].loc[date]["Close"]
- 1
)
else:
ret = 0.0
y_vals.append(ret)
y_vals.append(ret)
valid_seqs_for_y.append(node_sequences[i])
valid_tickers_for_y.append(ticker)
if not y_vals:
continue
if len(valid_tickers_for_y) < len(node_tickers):
# Rebuild x and edges using only stocks with valid targets
x = torch.tensor(np.array(valid_seqs_for_y), dtype=torch.float32)
mean = x.mean(dim=0, keepdim=True)
std = x.std(dim=0, keepdim=True).clamp(min=1e-8)
x = (x - mean) / std
edge_index, edge_weight = self._build_edges(
valid_tickers_for_y, date, pit_cache
)
node_tickers = valid_tickers_for_y
y = torch.tensor(y_vals, dtype=torch.float32).unsqueeze(1)