feat: integrate chatbox research with datasets and backtests

This commit is contained in:
yuxuanhui
2026-09-08 12:43:00 +08:00
parent 43336ad960
commit aef8e1d310
37 changed files with 1421 additions and 42 deletions
+70
View File
@@ -0,0 +1,70 @@
"""Read provenance from saved results, retaining every experiment for an Alpha."""
from collections import defaultdict
from fastapi import HTTPException
from fastapi.encoders import jsonable_encoder
from sqlalchemy import func, select
from ..models import Alpha, BacktestItem, BacktestResult, BacktestRun
def saved_sources():
"""Only persisted results establish provenance; pending platform IDs do not."""
return (
select(BacktestResult, BacktestItem, BacktestRun)
.select_from(BacktestResult)
.join(BacktestItem, BacktestResult.item_id == BacktestItem.id)
.join(BacktestRun, BacktestItem.run_id == BacktestRun.id)
)
def source_alpha_ids(source=None, source_reference=None, research_id=None, backtest_run_id=None):
"""An IN subquery keeps list counts and exports independent of source multiplicity."""
query = saved_sources().with_only_columns(BacktestResult.alpha_id)
for key, value in (("kind", source), ("reference", source_reference), ("research_id", research_id)):
if value:
query = query.where(BacktestRun.source[key].as_string() == value)
if backtest_run_id:
query = query.where(BacktestRun.id == backtest_run_id)
return query
async def source_kinds(db, alpha_ids=None):
query = saved_sources().with_only_columns(BacktestResult.alpha_id, BacktestRun.source["kind"].as_string())
if alpha_ids is not None:
query = query.where(BacktestResult.alpha_id.in_(alpha_ids))
values = defaultdict(list)
for alpha_id, kind in await db.execute(query.distinct()):
if kind:
values[alpha_id].append(kind)
return {alpha_id: sorted(kinds) for alpha_id, kinds in values.items()}
async def alpha_sources(db, alpha_id, limit=25, offset=0):
if not await db.get(Alpha, alpha_id):
raise HTTPException(404, "Alpha 尚未同步")
query = saved_sources().where(BacktestResult.alpha_id == alpha_id)
total = await db.scalar(select(func.count()).select_from(query.subquery()))
rows = await db.execute(
query.order_by(BacktestResult.observed_at.desc(), BacktestResult.item_id).limit(limit).offset(offset)
)
return jsonable_encoder(
{
"alpha_id": alpha_id,
"total": total,
"limit": limit,
"offset": offset,
"items": [
{
"backtest_run_id": run.id,
"name": run.name,
"source": run.source,
"item_id": item.id,
"client_item_id": item.client_item_id,
"observed_at": result.observed_at,
}
for result, item, run in rows
],
}
)