From 0727f28f77ea5372dc908bc65161379e317ff2f3 Mon Sep 17 00:00:00 2001 From: agentson Date: Mon, 23 Feb 2026 12:53:41 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=A7=84=ED=99=94=20=EC=A0=84=EB=9E=B5?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=203=EA=B0=9C=20=EB=93=A4=EC=97=AC?= =?UTF-8?q?=EC=93=B0=EA=B8=B0=20=EA=B5=AC=EB=AC=B8=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(issue=20#215)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AI가 evaluate() 메서드 내부에 또 다른 evaluate() 함수를 중첩 정의하는 실수로 생성된 IndentationError 수정. 각 파일별 수정 내용: - v20260220_210124_evolved.py: 중첩 def evaluate 제거, 상수/로직 8칸으로 정규화 - v20260220_210159_evolved.py: 중첩 def evaluate 제거, 16칸→8칸 들여쓰기 수정 - v20260220_210244_evolved.py: 12칸→8칸 들여쓰기 수정 Co-Authored-By: Claude Sonnet 4.6 --- src/strategies/v20260220_210124_evolved.py | 114 +++++++++++++++++++++ src/strategies/v20260220_210159_evolved.py | 97 ++++++++++++++++++ src/strategies/v20260220_210244_evolved.py | 88 ++++++++++++++++ 3 files changed, 299 insertions(+) create mode 100644 src/strategies/v20260220_210124_evolved.py create mode 100644 src/strategies/v20260220_210159_evolved.py create mode 100644 src/strategies/v20260220_210244_evolved.py diff --git a/src/strategies/v20260220_210124_evolved.py b/src/strategies/v20260220_210124_evolved.py new file mode 100644 index 0000000..0eb6a18 --- /dev/null +++ b/src/strategies/v20260220_210124_evolved.py @@ -0,0 +1,114 @@ +"""Auto-generated strategy: v20260220_210124 + +Generated at: 2026-02-20T21:01:24.706847+00:00 +Rationale: Auto-evolved from 6 failures. Primary failure markets: ['US_AMEX', 'US_NYSE', 'US_NASDAQ']. Average loss: -194.69 +""" + +from __future__ import annotations +from typing import Any +from src.strategies.base import BaseStrategy + + +class Strategy_v20260220_210124(BaseStrategy): + """Strategy: v20260220_210124""" + + def evaluate(self, market_data: dict[str, Any]) -> dict[str, Any]: + import datetime + + # --- Strategy Constants --- + # Minimum price for a stock to be considered for trading (avoids penny stocks) + MIN_PRICE = 5.0 + + # Momentum signal thresholds (stricter than previous failures) + MOMENTUM_PRICE_CHANGE_THRESHOLD = 7.0 # % price change + MOMENTUM_VOLUME_RATIO_THRESHOLD = 4.0 # X times average volume + + # Oversold signal thresholds (more conservative) + OVERSOLD_RSI_THRESHOLD = 25.0 # RSI value (lower means more oversold) + + # Confidence levels + CONFIDENCE_HOLD = 30 + CONFIDENCE_BUY_OVERSOLD = 65 + CONFIDENCE_BUY_MOMENTUM = 85 + CONFIDENCE_BUY_STRONG_MOMENTUM = 90 # For higher-priced stocks with strong momentum + + # Market hours in UTC (9:30 AM ET to 4:00 PM ET) + MARKET_OPEN_UTC = datetime.time(14, 30) + MARKET_CLOSE_UTC = datetime.time(21, 0) + + # Volatile periods within market hours (UTC) to avoid + # First hour after open (14:30 UTC - 15:30 UTC) + VOLATILE_OPEN_END_UTC = datetime.time(15, 30) + # Last 30 minutes before close (20:30 UTC - 21:00 UTC) + VOLATILE_CLOSE_START_UTC = datetime.time(20, 30) + + current_price = market_data.get('current_price') + price_change_pct = market_data.get('price_change_pct') + volume_ratio = market_data.get('volume_ratio') # Assumed pre-computed indicator + rsi = market_data.get('rsi') # Assumed pre-computed indicator + timestamp_str = market_data.get('timestamp') + + action = "HOLD" + confidence = CONFIDENCE_HOLD + rationale = "Initial HOLD: No clear signal or conditions not met." + + # --- 1. Basic Data Validation --- + if current_price is None or price_change_pct is None: + return {"action": "HOLD", "confidence": CONFIDENCE_HOLD, + "rationale": "Insufficient core data (price or price change) to evaluate."} + + # --- 2. Price Filter: Avoid low-priced/penny stocks --- + if current_price < MIN_PRICE: + return {"action": "HOLD", "confidence": CONFIDENCE_HOLD, + "rationale": f"Avoiding low-priced stock (${current_price:.2f} < ${MIN_PRICE:.2f})."} + + # --- 3. Time Filter: Only trade during core market hours --- + if timestamp_str: + try: + dt_object = datetime.datetime.fromisoformat(timestamp_str) + current_time_utc = dt_object.time() + + if not (MARKET_OPEN_UTC <= current_time_utc < MARKET_CLOSE_UTC): + return {"action": "HOLD", "confidence": CONFIDENCE_HOLD, + "rationale": f"Avoiding trade outside core market hours ({current_time_utc} UTC)."} + + if (MARKET_OPEN_UTC <= current_time_utc < VOLATILE_OPEN_END_UTC) or \ + (VOLATILE_CLOSE_START_UTC <= current_time_utc < MARKET_CLOSE_UTC): + return {"action": "HOLD", "confidence": CONFIDENCE_HOLD, + "rationale": f"Avoiding trade during volatile market open/close periods ({current_time_utc} UTC)."} + + except ValueError: + rationale += " (Warning: Malformed timestamp, time filters skipped)" + + # --- Initialize signal states --- + has_momentum_buy_signal = False + has_oversold_buy_signal = False + + # --- 4. Evaluate Enhanced Buy Signals --- + + # Momentum Buy Signal + if volume_ratio is not None and \ + price_change_pct > MOMENTUM_PRICE_CHANGE_THRESHOLD and \ + volume_ratio > MOMENTUM_VOLUME_RATIO_THRESHOLD: + has_momentum_buy_signal = True + rationale = f"Momentum BUY: Price change {price_change_pct:.2f}%, Volume {volume_ratio:.2f}x." + confidence = CONFIDENCE_BUY_MOMENTUM + if current_price >= 10.0: + confidence = CONFIDENCE_BUY_STRONG_MOMENTUM + + # Oversold Buy Signal + if rsi is not None and rsi < OVERSOLD_RSI_THRESHOLD: + has_oversold_buy_signal = True + if not has_momentum_buy_signal: + rationale = f"Oversold BUY: RSI {rsi:.2f}." + confidence = CONFIDENCE_BUY_OVERSOLD + if current_price >= 10.0: + confidence = min(CONFIDENCE_BUY_OVERSOLD + 5, 80) + + # --- 5. Decision Logic --- + if has_momentum_buy_signal: + action = "BUY" + elif has_oversold_buy_signal: + action = "BUY" + + return {"action": action, "confidence": confidence, "rationale": rationale} diff --git a/src/strategies/v20260220_210159_evolved.py b/src/strategies/v20260220_210159_evolved.py new file mode 100644 index 0000000..b3b7248 --- /dev/null +++ b/src/strategies/v20260220_210159_evolved.py @@ -0,0 +1,97 @@ +"""Auto-generated strategy: v20260220_210159 + +Generated at: 2026-02-20T21:01:59.391523+00:00 +Rationale: Auto-evolved from 6 failures. Primary failure markets: ['US_AMEX', 'US_NYSE', 'US_NASDAQ']. Average loss: -194.69 +""" + +from __future__ import annotations +from typing import Any +from src.strategies.base import BaseStrategy + + +class Strategy_v20260220_210159(BaseStrategy): + """Strategy: v20260220_210159""" + + def evaluate(self, market_data: dict[str, Any]) -> dict[str, Any]: + import datetime + + current_price = market_data.get('current_price') + price_change_pct = market_data.get('price_change_pct') + volume_ratio = market_data.get('volume_ratio') + rsi = market_data.get('rsi') + timestamp_str = market_data.get('timestamp') + market_name = market_data.get('market') + + # Default action + action = "HOLD" + confidence = 0 + rationale = "No strong signal or conditions not met." + + # --- FAILURE PATTERN AVOIDANCE --- + + # 1. Avoid low-priced/penny stocks + MIN_PRICE_THRESHOLD = 5.0 # USD + if current_price is not None and current_price < MIN_PRICE_THRESHOLD: + rationale = ( + f"HOLD: Stock price (${current_price:.2f}) is below minimum threshold " + f"(${MIN_PRICE_THRESHOLD:.2f}). Past failures consistently involved low-priced stocks." + ) + return {"action": action, "confidence": confidence, "rationale": rationale} + + # 2. Avoid early market hour volatility + if timestamp_str: + try: + dt_obj = datetime.datetime.fromisoformat(timestamp_str) + utc_hour = dt_obj.hour + utc_minute = dt_obj.minute + + if (utc_hour == 14 and utc_minute < 45) or (utc_hour == 13 and utc_minute >= 30): + rationale = ( + f"HOLD: Trading during early market hours (UTC {utc_hour}:{utc_minute}), " + f"a period identified with past failures due to high volatility." + ) + return {"action": action, "confidence": confidence, "rationale": rationale} + except ValueError: + pass + + # --- IMPROVED BUY STRATEGY --- + + # Momentum BUY signal + if volume_ratio is not None and price_change_pct is not None: + if price_change_pct > 7.0 and volume_ratio > 3.0: + action = "BUY" + confidence = 70 + rationale = "Improved BUY: Momentum signal with high volume and above price threshold." + + if market_name == 'US_AMEX': + confidence = max(55, confidence - 5) + rationale += " (Adjusted lower for AMEX market's higher risk profile)." + elif market_name == 'US_NASDAQ' and price_change_pct > 20: + confidence = max(50, confidence - 10) + rationale += " (Adjusted lower for aggressive NASDAQ momentum volatility)." + + if price_change_pct > 15.0: + confidence = max(50, confidence - 5) + rationale += " (Caution: Very high daily price change, potential for reversal)." + + return {"action": action, "confidence": confidence, "rationale": rationale} + + # Oversold BUY signal + if rsi is not None and price_change_pct is not None: + if rsi < 30 and price_change_pct < -3.0: + action = "BUY" + confidence = 65 + rationale = "Improved BUY: Oversold signal with recent decline and above price threshold." + + if market_name == 'US_AMEX': + confidence = max(50, confidence - 5) + rationale += " (Adjusted lower for AMEX market's higher risk on oversold assets)." + + if price_change_pct < -10.0: + confidence = max(45, confidence - 10) + rationale += " (Caution: Very steep decline, potential falling knife)." + + return {"action": action, "confidence": confidence, "rationale": rationale} + + # If no specific BUY signal, default to HOLD + return {"action": action, "confidence": confidence, "rationale": rationale} diff --git a/src/strategies/v20260220_210244_evolved.py b/src/strategies/v20260220_210244_evolved.py new file mode 100644 index 0000000..c27362d --- /dev/null +++ b/src/strategies/v20260220_210244_evolved.py @@ -0,0 +1,88 @@ +"""Auto-generated strategy: v20260220_210244 + +Generated at: 2026-02-20T21:02:44.387355+00:00 +Rationale: Auto-evolved from 6 failures. Primary failure markets: ['US_AMEX', 'US_NYSE', 'US_NASDAQ']. Average loss: -194.69 +""" + +from __future__ import annotations +from typing import Any +from src.strategies.base import BaseStrategy + + +class Strategy_v20260220_210244(BaseStrategy): + """Strategy: v20260220_210244""" + + def evaluate(self, market_data: dict[str, Any]) -> dict[str, Any]: + from datetime import datetime + + # Extract required data points safely + current_price = market_data.get("current_price") + price_change_pct = market_data.get("price_change_pct") + volume_ratio = market_data.get("volume_ratio") + rsi = market_data.get("rsi") + timestamp_str = market_data.get("timestamp") + market_name = market_data.get("market") + stock_code = market_data.get("stock_code", "UNKNOWN") + + # Default action is HOLD with conservative confidence and rationale + action = "HOLD" + confidence = 50 + rationale = f"No strong BUY signal for {stock_code} or awaiting more favorable conditions after avoiding known failure patterns." + + # --- 1. Failure Pattern Avoidance Filters --- + + # A. Avoid low-priced (penny) stocks + if current_price is not None and current_price < 5.0: + return { + "action": "HOLD", + "confidence": 50, + "rationale": f"AVOID {stock_code}: Stock price (${current_price:.2f}) is below minimum threshold ($5.00) for BUY action. Identified past failures on highly volatile, low-priced stocks." + } + + # B. Avoid initiating BUY trades during identified high-volatility hours + if timestamp_str: + try: + trade_hour = datetime.fromisoformat(timestamp_str).hour + if trade_hour in [14, 20]: + return { + "action": "HOLD", + "confidence": 50, + "rationale": f"AVOID {stock_code}: Trading during historically volatile hour ({trade_hour} UTC) where previous BUYs resulted in losses. Prefer to observe market stability." + } + except ValueError: + pass + + # C. Be cautious with extreme momentum spikes + if volume_ratio is not None and price_change_pct is not None: + if volume_ratio >= 9.0 and price_change_pct >= 15.0: + return { + "action": "HOLD", + "confidence": 50, + "rationale": f"AVOID {stock_code}: Extreme short-term momentum detected (price change: +{price_change_pct:.2f}%, volume ratio: {volume_ratio:.1f}x). Historical failures indicate buying into such rapid spikes often leads to reversals." + } + + # D. Be cautious with "oversold" signals without further confirmation + if rsi is not None and rsi < 30: + return { + "action": "HOLD", + "confidence": 50, + "rationale": f"AVOID {stock_code}: Oversold signal (RSI={rsi:.1f}) detected. While often a BUY signal, historical failures on similar 'oversold' trades suggest waiting for stronger confirmation." + } + + # --- 2. Improved BUY Signal Generation --- + if volume_ratio is not None and 2.0 <= volume_ratio < 9.0 and \ + price_change_pct is not None and 2.0 <= price_change_pct < 15.0: + + action = "BUY" + confidence = 70 + rationale = f"BUY {stock_code}: Moderate momentum detected (price change: +{price_change_pct:.2f}%, volume ratio: {volume_ratio:.1f}x). Passed filters for price and extreme momentum, avoiding past failure patterns." + + if market_name in ["US_AMEX", "US_NASDAQ"]: + confidence = max(60, confidence - 5) + rationale += f" Adjusted confidence for {market_name} market characteristics." + elif market_name == "US_NYSE": + confidence = max(65, confidence) + + confidence = max(50, min(85, confidence)) + + return {"action": action, "confidence": confidence, "rationale": rationale}