feat(selection): implement gold brick resonance strategy with evaluation and logging enhancements
This commit is contained in:
@@ -14,10 +14,16 @@ from zhixing_server.modules.selection.application.chart import (
|
||||
SelectionChart,
|
||||
SelectionChartNotFound,
|
||||
)
|
||||
from zhixing_server.modules.selection.application.evaluate_gold_brick import (
|
||||
EvaluateGoldBrick,
|
||||
)
|
||||
from zhixing_server.modules.selection.application.run import (
|
||||
RunZhixingB1,
|
||||
)
|
||||
from zhixing_server.modules.selection.domain.models import SelectionSignal
|
||||
from zhixing_server.modules.selection.domain.models import (
|
||||
SelectionSignal,
|
||||
SelectionStrategyName,
|
||||
)
|
||||
from zhixing_server.modules.selection.domain.pattern_scoring import (
|
||||
PatternScore,
|
||||
ZhixingB1PatternScorer,
|
||||
@@ -45,7 +51,7 @@ selection_router = APIRouter()
|
||||
_SELECTION_POOL_CACHE_LOCK = threading.Lock()
|
||||
_SELECTION_POOL_CACHE: dict[tuple[str, int], SelectionPostgresPool] = {}
|
||||
|
||||
StrategyValue = Literal["zhixing_b1"]
|
||||
StrategyValue = SelectionStrategyName
|
||||
SelectionStatusValue = Literal[
|
||||
"no_data",
|
||||
"running",
|
||||
@@ -216,6 +222,7 @@ def get_selection_service(
|
||||
return RunZhixingB1(
|
||||
reader,
|
||||
store,
|
||||
evaluators={"gold_brick": EvaluateGoldBrick(reader)},
|
||||
pattern_case_loader=pattern_case_loader,
|
||||
pattern_scorer=ZhixingB1PatternScorer(),
|
||||
pattern_scoring_enabled=settings.selection_pattern_scoring_enabled,
|
||||
@@ -324,7 +331,9 @@ def get_selection_run(
|
||||
page: Annotated[int, Query(ge=1)] = 1,
|
||||
page_size: Annotated[int, Query(ge=1, le=100)] = 10,
|
||||
search: Annotated[str | None, Query(max_length=100)] = None,
|
||||
category: Literal["pullback", "oversold", "original"] | None = None,
|
||||
category: Literal[
|
||||
"pullback", "oversold", "original", "resonance"
|
||||
] | None = None,
|
||||
sort: Literal["code", "score_desc", "score_asc"] = "code",
|
||||
) -> SelectionResultsResponse:
|
||||
"""Return one run for asynchronous polling."""
|
||||
@@ -347,7 +356,9 @@ def get_selection_results(
|
||||
page: Annotated[int, Query(ge=1)] = 1,
|
||||
page_size: Annotated[int, Query(ge=1, le=100)] = 10,
|
||||
search: Annotated[str | None, Query(max_length=100)] = None,
|
||||
category: Literal["pullback", "oversold", "original"] | None = None,
|
||||
category: Literal[
|
||||
"pullback", "oversold", "original", "resonance"
|
||||
] | None = None,
|
||||
sort: Literal["code", "score_desc", "score_asc"] = "code",
|
||||
) -> SelectionResultsResponse:
|
||||
"""Return the current persisted result for a strategy and optional date."""
|
||||
@@ -410,7 +421,13 @@ def _run_response(run: SelectionRun, *, query: SelectionResultQuery) -> Selectio
|
||||
reason=item.reason,
|
||||
)
|
||||
for item in run.items
|
||||
if item.status in {"insufficient_history", "missing_target_bar", "data_error"}
|
||||
if item.status
|
||||
in {
|
||||
"insufficient_history",
|
||||
"missing_target_bar",
|
||||
"missing_turnover_rate",
|
||||
"data_error",
|
||||
}
|
||||
],
|
||||
stocks=[
|
||||
SelectionStockResponse(
|
||||
@@ -496,7 +513,7 @@ def _result_query(
|
||||
page: int,
|
||||
page_size: int,
|
||||
search: str | None,
|
||||
category: Literal["pullback", "oversold", "original"] | None,
|
||||
category: Literal["pullback", "oversold", "original", "resonance"] | None,
|
||||
sort: Literal["code", "score_desc", "score_asc"],
|
||||
) -> SelectionResultQuery:
|
||||
"""Normalize HTTP query values before handing them to the selection port."""
|
||||
|
||||
Reference in New Issue
Block a user