feat: refactor portfolio strategy references
This commit is contained in:
@@ -45,19 +45,33 @@ def _to_portfolio_summary(portfolio: Portfolio):
|
||||
broker=portfolio.broker,
|
||||
status=portfolio.status,
|
||||
symbol=portfolio.symbol,
|
||||
strategy_name=portfolio.strategy_name,
|
||||
strategy_params=portfolio.strategy_params,
|
||||
cash_balance=portfolio.cash_balance,
|
||||
asset_quantity=portfolio.asset_quantity,
|
||||
price=portfolio.price,
|
||||
profit_buffer=portfolio.profit_buffer,
|
||||
current_strategy_set_id=portfolio.current_strategy_set_id,
|
||||
active_strategy_id=portfolio.active_strategy_id,
|
||||
avabile_strategies=portfolio.avabile_strategies,
|
||||
created_at=portfolio.created_at,
|
||||
updated_at=portfolio.updated_at,
|
||||
last_trade_at=portfolio.last_trade_at,
|
||||
)
|
||||
|
||||
|
||||
def _parse_strategy_config(config: str) -> dict[str, object]:
|
||||
try:
|
||||
parsed = json.loads(config) if config else {}
|
||||
except json.JSONDecodeError:
|
||||
return {}
|
||||
return parsed if isinstance(parsed, dict) else {}
|
||||
|
||||
|
||||
def _merge_strategy_ids(active_strategy_id: str | None, strategy_ids: list[str] | None) -> list[str] | None:
|
||||
normalized = list(strategy_ids or [])
|
||||
if active_strategy_id and active_strategy_id not in normalized:
|
||||
normalized.append(active_strategy_id)
|
||||
return normalized or None
|
||||
|
||||
|
||||
def _to_strategy_set_response(strategy_set: StrategySet | None):
|
||||
from app.schemas.portfolio import StrategySetResponse
|
||||
|
||||
@@ -124,39 +138,68 @@ class PortfolioService:
|
||||
return _to_detail_response(status_result)
|
||||
|
||||
def create_portfolio(self, payload: CreatePortfolioRequest) -> PortfolioDetailResponse:
|
||||
strategy_set = self._repository.get_or_create_strategy_set(
|
||||
payload.strategy_name,
|
||||
json.dumps(payload.strategy_params, sort_keys=True, ensure_ascii=True),
|
||||
)
|
||||
active_strategy_id = payload.active_strategy_id
|
||||
if active_strategy_id is None:
|
||||
strategy_set = self._repository.get_or_create_strategy_set(
|
||||
payload.strategy_name,
|
||||
json.dumps(payload.strategy_params, sort_keys=True, ensure_ascii=True),
|
||||
)
|
||||
active_strategy_id = strategy_set.id
|
||||
avabile_strategies = _merge_strategy_ids(active_strategy_id, payload.avabile_strategies)
|
||||
portfolio = self._repository.create_portfolio(
|
||||
payload.portfolio_id,
|
||||
broker=payload.broker,
|
||||
status=payload.status,
|
||||
symbol=payload.symbol,
|
||||
strategy_name=payload.strategy_name,
|
||||
strategy_params=payload.strategy_params,
|
||||
cash_balance=payload.cash_balance,
|
||||
asset_quantity=payload.asset_quantity,
|
||||
asset_price=payload.asset_price,
|
||||
profit_buffer=payload.profit_buffer,
|
||||
)
|
||||
portfolio = self._repository.update_portfolio(
|
||||
payload.portfolio_id,
|
||||
current_strategy_set_id=strategy_set.id,
|
||||
active_strategy_id=active_strategy_id,
|
||||
avabile_strategies=avabile_strategies,
|
||||
)
|
||||
return self.get_portfolio_status(portfolio_id=portfolio.portfolio_id, recent_trades=5)
|
||||
|
||||
def update_portfolio(self, portfolio_id: str, payload: UpdatePortfolioRequest) -> PortfolioDetailResponse:
|
||||
fields = payload.model_dump(exclude_none=True)
|
||||
current = self._repository.get(portfolio_id)
|
||||
|
||||
if "strategy_name" in fields or "strategy_params" in fields:
|
||||
current = self._repository.get(portfolio_id)
|
||||
strategy_name = fields.get("strategy_name", current.strategy_name)
|
||||
strategy_params = fields.get("strategy_params", current.strategy_params)
|
||||
current_strategy_set = None
|
||||
if current.active_strategy_id:
|
||||
current_strategy_set = self._repository.get_strategy_set(current.active_strategy_id)
|
||||
|
||||
strategy_name = fields.get("strategy_name")
|
||||
if strategy_name is None and current_strategy_set is not None:
|
||||
strategy_name = current_strategy_set.name
|
||||
if strategy_name is None:
|
||||
raise ValueError("strategy_name is required when no active strategy is set")
|
||||
|
||||
strategy_params = fields.get("strategy_params")
|
||||
if strategy_params is None and current_strategy_set is not None:
|
||||
strategy_params = _parse_strategy_config(current_strategy_set.config)
|
||||
if strategy_params is None:
|
||||
strategy_params = {}
|
||||
|
||||
strategy_set = self._repository.get_or_create_strategy_set(
|
||||
strategy_name,
|
||||
json.dumps(strategy_params, sort_keys=True, ensure_ascii=True),
|
||||
)
|
||||
fields["current_strategy_set_id"] = strategy_set.id
|
||||
fields["active_strategy_id"] = strategy_set.id
|
||||
fields["avabile_strategies"] = _merge_strategy_ids(
|
||||
strategy_set.id,
|
||||
fields.get("avabile_strategies", current.avabile_strategies),
|
||||
)
|
||||
|
||||
elif "active_strategy_id" in fields:
|
||||
fields["avabile_strategies"] = _merge_strategy_ids(
|
||||
fields.get("active_strategy_id"),
|
||||
fields.get("avabile_strategies", current.avabile_strategies),
|
||||
)
|
||||
|
||||
fields.pop("strategy_name", None)
|
||||
fields.pop("strategy_params", None)
|
||||
|
||||
self._repository.update_portfolio(portfolio_id, **fields)
|
||||
return self.get_portfolio_status(portfolio_id=portfolio_id, recent_trades=5)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user