feat: Add core trading modules for risk management, backtesting, and execution algorithms, alongside a new ML transparency widget and related frontend dependencies.
Some checks are pending
Documentation / build-docs (push) Waiting to run
Tests / test (macos-latest, 3.11) (push) Waiting to run
Tests / test (macos-latest, 3.12) (push) Waiting to run
Tests / test (macos-latest, 3.13) (push) Waiting to run
Tests / test (macos-latest, 3.14) (push) Waiting to run
Tests / test (ubuntu-latest, 3.11) (push) Waiting to run
Tests / test (ubuntu-latest, 3.12) (push) Waiting to run
Tests / test (ubuntu-latest, 3.13) (push) Waiting to run
Tests / test (ubuntu-latest, 3.14) (push) Waiting to run

This commit is contained in:
2025-12-31 21:25:06 -05:00
parent 099432bf3f
commit 7bd6be64a4
743 changed files with 8617 additions and 5042 deletions

View File

@@ -8,6 +8,7 @@ import pandas as pd
from src.core.database import MarketData, get_database
from src.data.pricing_service import get_pricing_service
from src.data.indicators import get_indicators
from src.core.config import get_config
router = APIRouter()
@@ -278,3 +279,130 @@ async def get_spread_data(
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/indicators/{symbol:path}")
async def get_indicators_data(
symbol: str,
timeframe: str = "1h",
limit: int = 100,
exchange: str = "coinbase",
indicators: str = Query("", description="Comma-separated list of indicators (e.g., 'sma_20,ema_20,rsi,macd,bollinger_bands')")
):
"""Get OHLCV data with technical indicators for a symbol.
Supported indicators:
- sma_<period>: Simple Moving Average (e.g., sma_20, sma_50)
- ema_<period>: Exponential Moving Average (e.g., ema_20, ema_50)
- rsi: Relative Strength Index
- macd: MACD (returns macd, signal, histogram)
- bollinger_bands: Bollinger Bands (returns upper, middle, lower)
- atr: Average True Range
- obv: On Balance Volume
- adx: Average Directional Index
"""
from sqlalchemy import select
try:
# Fetch OHLCV data first (reuse existing logic)
ohlcv_data = []
try:
db = get_database()
async with db.get_session() as session:
stmt = select(MarketData).filter_by(
symbol=symbol,
timeframe=timeframe,
exchange=exchange
).order_by(MarketData.timestamp.desc()).limit(limit)
result = await session.execute(stmt)
data = result.scalars().all()
if data:
ohlcv_data = [
{
"time": int(d.timestamp.timestamp()),
"open": float(d.open),
"high": float(d.high),
"low": float(d.low),
"close": float(d.close),
"volume": float(d.volume)
}
for d in reversed(data)
]
except Exception:
pass
# If no DB data, fetch from pricing service
if not ohlcv_data:
try:
pricing_service = get_pricing_service()
ohlcv_raw = pricing_service.get_ohlcv(
symbol=symbol,
timeframe=timeframe,
limit=limit
)
if ohlcv_raw:
ohlcv_data = [
{
"time": int(candle[0] / 1000),
"open": float(candle[1]),
"high": float(candle[2]),
"low": float(candle[3]),
"close": float(candle[4]),
"volume": float(candle[5])
}
for candle in ohlcv_raw
]
except Exception:
pass
if not ohlcv_data:
return {"ohlcv": [], "indicators": {}}
# Convert to DataFrame for indicator calculation
df = pd.DataFrame(ohlcv_data)
df.set_index('time', inplace=True)
# Prepare DataFrame for indicators (needs columns: open, high, low, close, volume)
df_ind = pd.DataFrame({
'open': df['open'],
'high': df['high'],
'low': df['low'],
'close': df['close'],
'volume': df['volume']
})
# Parse indicator list
indicator_list = [ind.strip() for ind in indicators.split(',') if ind.strip()] if indicators else []
# Calculate indicators
indicators_calc = get_indicators()
if indicator_list:
df_with_indicators = indicators_calc.calculate_all(df_ind, indicators=indicator_list)
else:
# Default indicators if none specified
df_with_indicators = indicators_calc.calculate_all(df_ind)
# Build response
result_ohlcv = df.reset_index().to_dict('records')
# Extract indicator data
indicator_data = {}
for col in df_with_indicators.columns:
if col not in ['open', 'high', 'low', 'close', 'volume']:
# Convert NaN to None for JSON serialization
values = df_with_indicators[col].replace({pd.NA: None, pd.NaT: None}).tolist()
indicator_data[col] = [
float(v) if v is not None and not pd.isna(v) else None
for v in values
]
return {
"ohlcv": result_ohlcv,
"indicators": indicator_data,
"times": [int(t) for t in df.index.tolist()]
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))