rebuild(stage-7): deliver ladder and sector rotation
This commit is contained in:
@@ -107,6 +107,68 @@ class DataGateway:
|
||||
row = self._repository.latest_summary(connection, context.actual_date)
|
||||
return {"context": context, "values": json.loads(str(row["payload_json"])) if row else None}
|
||||
|
||||
def snapshot_inputs(
|
||||
self, trade_date: str, previous_trade_date: str
|
||||
) -> dict[str, Any]:
|
||||
provider = self._provider(DataSource.TUSHARE)
|
||||
self._policy.assert_allowed(provider.source, DataUsage.CALCULATION)
|
||||
return provider.snapshot_inputs(trade_date, previous_trade_date)
|
||||
|
||||
def sector_members(
|
||||
self, trade_date: str, sector_name: str, representative: str
|
||||
) -> dict[str, Any]:
|
||||
with self._database.read() as connection:
|
||||
cached = self._repository.sector_members(connection, trade_date, sector_name)
|
||||
if cached:
|
||||
return json.loads(str(cached["payload_json"]))
|
||||
provider = self._provider(DataSource.TUSHARE)
|
||||
self._policy.assert_allowed(provider.source, DataUsage.CALCULATION)
|
||||
result = provider.sector_members(representative, trade_date)
|
||||
if not result.rows:
|
||||
raise MarketDataUnavailable("该板块暂无可核验的申万成分股")
|
||||
rows = sorted(
|
||||
(dict(row) for row in result.rows),
|
||||
key=lambda row: (
|
||||
bool(row.get("quoted")),
|
||||
_number(row.get("change")),
|
||||
_number(row.get("amount")),
|
||||
),
|
||||
reverse=True,
|
||||
)
|
||||
payload = {
|
||||
"trade_date": trade_date,
|
||||
"sector_name": str(rows[0].get("sector_name") or sector_name),
|
||||
"sector_code": str(rows[0].get("sector_code") or ""),
|
||||
"member_count": len(rows),
|
||||
"quoted_count": sum(bool(row.get("quoted")) for row in rows),
|
||||
"coverage": round(result.metadata.coverage, 4),
|
||||
"items": [
|
||||
{
|
||||
"identifier": str(row.get("ts_code") or ""),
|
||||
"code": str(row.get("ts_code") or "").split(".")[0],
|
||||
"name": str(row.get("name") or ""),
|
||||
"change": row.get("change"),
|
||||
"open": row.get("open"),
|
||||
"close": row.get("close"),
|
||||
"amount": row.get("amount"),
|
||||
"quoted": bool(row.get("quoted")),
|
||||
}
|
||||
for row in rows
|
||||
],
|
||||
}
|
||||
with self._database.transaction() as connection:
|
||||
self._repository.save_sector_members(
|
||||
connection,
|
||||
trade_date=trade_date,
|
||||
sector_name=sector_name,
|
||||
sector_code=payload["sector_code"],
|
||||
observed_at=result.metadata.observed_at.isoformat(timespec="seconds"),
|
||||
source=result.metadata.source.value,
|
||||
coverage=result.metadata.coverage,
|
||||
payload=payload,
|
||||
)
|
||||
return payload
|
||||
|
||||
def search(self, query: str) -> tuple[MarketEntity, ...]:
|
||||
with self._database.read() as connection:
|
||||
return self._repository.search(connection, query)
|
||||
|
||||
Reference in New Issue
Block a user