Files
stockautomtion/app/engine/strategies/periodic.py
2026-07-16 23:55:16 +09:00

68 lines
2.5 KiB
Python

from __future__ import annotations
from datetime import datetime
from app.engine.strategies.base import BaseStrategy, Signal
class PeriodicStrategy(BaseStrategy):
"""정액(DCA) / 정률 투자 전략"""
def evaluate(self, current_price: dict, price_history: list[dict], holding_qty: int) -> Signal:
price = current_price.get("current_price", 0)
if price <= 0:
return Signal(action="hold", stock_code=self.stock_code)
invest_type = self.params.get("invest_type", "fixed_amount")
amount = self.params.get("amount", 100000)
ratio = self.params.get("ratio", 0.0)
invest_days = self.params.get("invest_days", [0, 1, 2, 3, 4])
invest_hour = self.params.get("invest_hour", 10)
invest_minute = self.params.get("invest_minute", 0)
min_price_drop = self.params.get("min_price_drop_percent", 0)
max_price = self.params.get("max_price", 0)
now = datetime.now()
if now.weekday() not in invest_days:
return Signal(action="hold", stock_code=self.stock_code)
if now.hour != invest_hour or now.minute != invest_minute:
return Signal(action="hold", stock_code=self.stock_code)
if max_price and price > max_price:
return Signal(
action="hold",
stock_code=self.stock_code,
reason=f"가격 상한 초과: {price} > {max_price}",
)
if min_price_drop and len(price_history) >= 2:
prev_close = price_history[-2].get("close", price)
if prev_close > 0:
drop_pct = (prev_close - price) / prev_close * 100
if drop_pct < min_price_drop:
return Signal(
action="hold",
stock_code=self.stock_code,
reason=f"가격 하락 미충족: {drop_pct:.2f}% < {min_price_drop}%",
)
if invest_type == "fixed_amount":
qty = max(1, amount // price)
elif invest_type == "fixed_ratio":
total_invest = self.params.get("total_capital", 100_000_000)
invest_amount = int(total_invest * ratio)
qty = max(1, invest_amount // price)
else:
qty = 1
return Signal(
action="buy",
stock_code=self.stock_code,
qty=qty,
price=price,
reason=f"정기투자: {invest_type}, {qty}",
confidence=1.0,
)