From 9c5e8c32f7b1cf10f79c4195b822468fdaca2d0d Mon Sep 17 00:00:00 2001 From: chrisnov-it Date: Tue, 23 Jun 2026 14:19:32 +0800 Subject: [PATCH] Refine strategies: fix IndexBreakoutPro, lower score inflation, enhance base class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix IndexBreakoutPro: added try/except for pandas_ta import (was crashing) - Re-enable IndexBreakoutPro in strategy_map (was disabled 'temporarily' with import error) - Lower inflated complexity scores: Hybrid 8→6, Crypto 12→7 (EXPERT→INTERMEDIATE) - Enhance BaseStrategy with get_stop_loss(), get_take_profit(), validate() methods - Fix mutable default arg (params: dict = {} → params: dict = None) Co-Authored-By: Claude --- core/strategies/base_strategy.py | 34 +++++++++++++++++++++++++-- core/strategies/index_breakout_pro.py | 5 +++- core/strategies/strategy_map.py | 33 +++++++++++++------------- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/core/strategies/base_strategy.py b/core/strategies/base_strategy.py index 463beef..b88664d 100644 --- a/core/strategies/base_strategy.py +++ b/core/strategies/base_strategy.py @@ -7,9 +7,9 @@ class BaseStrategy(ABC): Kelas dasar abstrak untuk semua strategi trading. Setiap strategi harus mewarisi kelas ini dan mengimplementasikan metode `analyze`. """ - def __init__(self, bot_instance, params: dict = {}): + def __init__(self, bot_instance, params: dict = None): self.bot = bot_instance - self.params = params + self.params = params or {} @abstractmethod def analyze(self, df): @@ -20,6 +20,36 @@ class BaseStrategy(ABC): """ raise NotImplementedError("Setiap strategi harus mengimplementasikan metode `analyze(df)`.") + def get_stop_loss(self, df, signal: str, price: float) -> float: + """ + Opsional: mengembalikan harga stop-loss yang disarankan berdasarkan logika strategi. + Default: 2% dari harga entry. Override di subclass untuk custom logic (berbasis ATR dll). + """ + if signal == "BUY": + return price * 0.98 + elif signal == "SELL": + return price * 1.02 + return 0.0 + + def get_take_profit(self, df, signal: str, price: float) -> float: + """ + Opsional: mengembalikan harga take-profit yang disarankan. + Default: 4% dari harga entry (risk-reward 2:1 dari default SL). + """ + if signal == "BUY": + return price * 1.04 + elif signal == "SELL": + return price * 0.96 + return 0.0 + + def validate(self, df) -> tuple: + """ + Opsional: memeriksa apakah kondisi pasar cocok untuk strategi ini. + Mengembalikan (valid: bool, reason: str). + Default: selalu valid. + """ + return True, "" + @classmethod def get_definable_params(cls): """ diff --git a/core/strategies/index_breakout_pro.py b/core/strategies/index_breakout_pro.py index ee06a52..01d0540 100644 --- a/core/strategies/index_breakout_pro.py +++ b/core/strategies/index_breakout_pro.py @@ -1,7 +1,10 @@ # core/strategies/index_breakout_pro.py import pandas as pd -import pandas_ta as ta +try: + import pandas_ta as ta +except ImportError: + from core.utils.pandas_ta_compat import ta from .base_strategy import BaseStrategy import logging diff --git a/core/strategies/strategy_map.py b/core/strategies/strategy_map.py index bc70bb0..6c43b46 100644 --- a/core/strategies/strategy_map.py +++ b/core/strategies/strategy_map.py @@ -13,8 +13,7 @@ from .turtle_breakout import TurtleBreakoutStrategy from .ichimoku_cloud import IchimokuCloudStrategy from .dynamic_breakout import DynamicBreakoutStrategy from .index_momentum import IndexMomentumStrategy -# TEMPORARILY DISABLED - needs import fix -# from .index_breakout_pro import IndexBreakoutProStrategy +from .index_breakout_pro import IndexBreakoutProStrategy from .beginner_defaults import BEGINNER_DEFAULTS STRATEGY_MAP = { @@ -31,7 +30,7 @@ STRATEGY_MAP = { 'ICHIMOKU_CLOUD': IchimokuCloudStrategy, 'DYNAMIC_BREAKOUT': DynamicBreakoutStrategy, 'INDEX_MOMENTUM': IndexMomentumStrategy, - # 'INDEX_BREAKOUT_PRO': IndexBreakoutProStrategy, # TEMPORARILY DISABLED + 'INDEX_BREAKOUT_PRO': IndexBreakoutProStrategy, } # Beginner-friendly strategy metadata @@ -124,18 +123,18 @@ STRATEGY_METADATA = { # 🚀 EXPERT 'QUANTUMBOTX_HYBRID': { - 'difficulty': 'EXPERT', - 'complexity_score': 8, + 'difficulty': 'INTERMEDIATE', + 'complexity_score': 6, 'recommended_for_beginners': False, - 'description': 'Multi-asset adaptive strategy', + 'description': 'Multi-indicator hybrid strategy for forex and crypto', 'market_types': ['FOREX', 'GOLD', 'CRYPTO'], 'learning_priority': 11 }, 'QUANTUMBOTX_CRYPTO': { - 'difficulty': 'EXPERT', - 'complexity_score': 12, + 'difficulty': 'INTERMEDIATE', + 'complexity_score': 7, 'recommended_for_beginners': False, - 'description': 'Crypto-specialized advanced system', + 'description': 'Crypto-specialized strategy with volatility management', 'market_types': ['CRYPTO'], 'learning_priority': 12 }, @@ -149,14 +148,14 @@ STRATEGY_METADATA = { 'market_types': ['INDICES'], 'learning_priority': 8 }, - # 'INDEX_BREAKOUT_PRO': { - # 'difficulty': 'ADVANCED', - # 'complexity_score': 7, - # 'recommended_for_beginners': False, - # 'description': 'Professional index breakout with institutional analysis', - # 'market_types': ['INDICES'], - # 'learning_priority': 10 - # } + 'INDEX_BREAKOUT_PRO': { + 'difficulty': 'ADVANCED', + 'complexity_score': 7, + 'recommended_for_beginners': False, + 'description': 'Professional index breakout with institutional analysis', + 'market_types': ['INDICES'], + 'learning_priority': 10 + } } def get_beginner_strategies():