149 lines
5.0 KiB
Python
149 lines
5.0 KiB
Python
"""Domain-owned AI capabilities; caller owns authorization and transactions."""
|
||
|
||
from pydantic import Field
|
||
|
||
from ..schemas import AlphaFilters, BulkInput, BulkUpdate, Contract, ResearchInput, ResearchUpdate
|
||
from .capabilities import Capability, EmptyArgs
|
||
|
||
|
||
class SearchArgs(Contract):
|
||
filters: AlphaFilters = Field(default_factory=AlphaFilters)
|
||
|
||
|
||
class AlphaArgs(Contract):
|
||
alpha_id: str = Field(min_length=1, max_length=100, pattern=r"^[A-Za-z0-9_-]+$")
|
||
|
||
|
||
class ResearchArgs(AlphaArgs):
|
||
changes: ResearchInput
|
||
|
||
|
||
async def search(ctx, args):
|
||
data = await ctx.business.search_alphas(args.filters)
|
||
return {**data, "filters": args.filters.model_dump(mode="json")}
|
||
|
||
|
||
async def pnl(ctx, args):
|
||
data = await ctx.business.get_alpha_pnl(args.alpha_id)
|
||
points = data.pop("points")
|
||
# Chart data is fetched by the UI; keep large series out of model context.
|
||
series = data.pop("series", [])
|
||
return {
|
||
**data,
|
||
"alpha_id": args.alpha_id,
|
||
"count": len(points),
|
||
"series": [{"id": item["id"], "label": item["label"]} for item in series],
|
||
"first": points[0] if points else None,
|
||
"last": points[-1] if points else None,
|
||
"null_count": sum(p["value"] is None for p in points),
|
||
}
|
||
|
||
|
||
async def research_preview(ctx, ids, changes):
|
||
"""Fix before/after values and versions using the same validation as execution."""
|
||
targets, versions = [], {}
|
||
for alpha_id in ids:
|
||
before = (await ctx.business.get_alpha(alpha_id))["research"]
|
||
after = {**before, **changes(before)}
|
||
ResearchInput.model_validate({k: after[k] for k in ("note", "tags", "favorite", "state")})
|
||
targets.append({"alpha_id": alpha_id, "before": before, "after": after})
|
||
versions[alpha_id] = before["version"]
|
||
return {"targets": targets, "versions": versions}
|
||
|
||
|
||
async def preview_research(ctx, args):
|
||
return await research_preview(
|
||
ctx, [args.alpha_id], lambda before: args.changes.model_dump(exclude_unset=True)
|
||
)
|
||
|
||
|
||
async def preview_bulk(ctx, args):
|
||
return await research_preview(
|
||
ctx,
|
||
args.alpha_ids,
|
||
lambda before: {
|
||
"tags": sorted((set(before["tags"]) | set(args.add_tags)) - set(args.remove_tags)),
|
||
**({"state": args.state} if args.state else {}),
|
||
},
|
||
)
|
||
|
||
|
||
async def update_research(ctx, args, preview):
|
||
return await ctx.business.update_research(
|
||
args.alpha_id,
|
||
ResearchUpdate(
|
||
**args.changes.model_dump(exclude_unset=True), version=preview["versions"][args.alpha_id]
|
||
),
|
||
)
|
||
|
||
|
||
async def update_bulk(ctx, args, preview):
|
||
return await ctx.business.bulk_update_research(
|
||
BulkUpdate(**args.model_dump(), versions=preview["versions"])
|
||
)
|
||
|
||
|
||
INSTRUCTIONS = "缺失指标保持未知;Turnover 0.15 表示15%。陈述依据、Alpha ID 和数据时间,区分当前页与全部结果。\n只传需要修改的研究字段。批量操作固定ID,最多100个。不要自行扩大选中范围。"
|
||
|
||
|
||
CAPABILITIES = (
|
||
Capability(
|
||
name="search_alphas",
|
||
schema=SearchArgs,
|
||
description="按明确筛选条件查询本地 Alpha。Turnover 0.15 表示 15%;支持分页,禁止把当前页当作全部结果。",
|
||
label="查询 Alpha",
|
||
renderer="alpha",
|
||
effect="query",
|
||
handler=search,
|
||
),
|
||
Capability(
|
||
name="get_alpha_facets",
|
||
schema=EmptyArgs,
|
||
description="获取可用地区、类型、状态、标签与本地 Alpha 总数。",
|
||
label="查询筛选选项",
|
||
renderer="alpha",
|
||
effect="query",
|
||
handler=lambda ctx, args: ctx.business.get_alpha_facets(),
|
||
),
|
||
Capability(
|
||
name="get_alpha",
|
||
schema=AlphaArgs,
|
||
description="读取指定 Alpha 的表达式、指标、已有检查和本地研究记录。",
|
||
label="读取 Alpha",
|
||
renderer="alpha",
|
||
effect="query",
|
||
handler=lambda ctx, args: ctx.business.get_alpha(args.alpha_id),
|
||
),
|
||
Capability(
|
||
name="get_alpha_pnl",
|
||
schema=AlphaArgs,
|
||
description="读取指定 Alpha 的 PnL 缓存摘要。缺失缓存时说明情况,不自动刷新。",
|
||
label="读取 PnL 缓存",
|
||
renderer="alpha",
|
||
effect="query",
|
||
handler=pnl,
|
||
),
|
||
Capability(
|
||
name="update_research",
|
||
schema=ResearchArgs,
|
||
description="提出指定 Alpha 的本地研究记录修改。仅传要修改的字段,等待用户在界面确认。",
|
||
label="修改研究记录",
|
||
renderer="alpha",
|
||
effect="confirm",
|
||
preview=preview_research,
|
||
execute=update_research,
|
||
refresh=("alphas",),
|
||
),
|
||
Capability(
|
||
name="bulk_update_research",
|
||
schema=BulkInput,
|
||
description="提出固定 1–100 个 Alpha 的批量标签或研究状态修改,等待用户确认。",
|
||
label="批量修改研究记录",
|
||
renderer="alpha",
|
||
effect="confirm",
|
||
preview=preview_bulk,
|
||
execute=update_bulk,
|
||
refresh=("alphas",),
|
||
),
|
||
)
|