44 lines
1.1 KiB
Python
44 lines
1.1 KiB
Python
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass
|
|
|
|
import pandas as pd
|
|
|
|
from app.core.logger import setup_logger
|
|
|
|
logger = setup_logger("strategy")
|
|
|
|
|
|
@dataclass
|
|
class Signal:
|
|
action: str # buy / sell / hold
|
|
stock_code: str
|
|
qty: int = 0
|
|
price: int = 0
|
|
reason: str = ""
|
|
confidence: float = 0.0
|
|
strategy_id: int | None = None
|
|
|
|
|
|
class BaseStrategy(ABC):
|
|
def __init__(self, stock_code: str, params: dict, strategy_id: int = 0) -> None:
|
|
self.stock_code = stock_code
|
|
self.params = params
|
|
self.strategy_id = strategy_id
|
|
self.name = self.__class__.__name__
|
|
|
|
@abstractmethod
|
|
def evaluate(self, current_price: dict, price_history: list[dict], holding_qty: int) -> Signal:
|
|
...
|
|
|
|
@staticmethod
|
|
def _to_dataframe(prices: list[dict]) -> pd.DataFrame:
|
|
if not prices:
|
|
return pd.DataFrame()
|
|
df = pd.DataFrame(prices)
|
|
for col in ["open", "high", "low", "close", "volume"]:
|
|
if col in df.columns:
|
|
df[col] = pd.to_numeric(df[col], errors="coerce")
|
|
return df
|