# *Feature Engineering* > **File:** `src/feature_eng.py` > **Class:** `FeatureEngineer` > **Framework:** Pure Polars (vectorized, tanpa loop, tanpa TA-Lib — bukan Pandas) --- ## Pipeline *Feature Engineering* ```mermaid flowchart LR A["OHLCV Data\n(open, high, low,\nclose, volume, time)"] --> B["calculate_all()"] subgraph B["calculate_all()"] direction TB B1["calculate_rsi()"] B2["calculate_atr()"] B3["calculate_macd()"] B4["calculate_bollinger_bands()"] B5["calculate_ema_crossover()"] B6["calculate_volume_features()"] B7["calculate_ml_features()\n(returns, volatility,\nlags, trend, time)"] B1 --> B2 --> B3 --> B4 --> B5 --> B6 --> B7 end B --> C["40+ Fitur Numerik"] C --> D["ML Ready\n(XGBoost Input)"] style A fill:#2d3748,stroke:#63b3ed,color:#fff style C fill:#2d3748,stroke:#48bb78,color:#fff style D fill:#2d3748,stroke:#f6ad55,color:#fff ``` > **Performa:** Seluruh pipeline dijalankan dalam **< 100ms** untuk 5000 bar menggunakan Pure Polars (vectorized, 10-100x lebih cepat dari Pandas loop). Menghasilkan **40+ fitur** yang siap digunakan model ML. --- ## Apa Itu *Feature Engineering*? *Feature Engineering* adalah proses **mengubah data harga mentah (OHLCV) menjadi 40+ fitur numerik** yang bisa dibaca oleh model machine learning. Ini adalah "mata" dari AI -- tanpa fitur yang baik, model tidak bisa belajar apapun. **Analogi:** *Feature Engineering* adalah **alat ukur** -- thermometer, barometer, kompas -- yang mengubah data mentah menjadi informasi bermakna. --- ## Flow Utama: `calculate_all()` ``` Input: DataFrame OHLCV (open, high, low, close, volume) | |-- calculate_rsi() -> rsi |-- calculate_atr() -> atr, atr_percent |-- calculate_macd() -> macd, macd_signal, macd_histogram |-- calculate_bollinger_bands() -> bb_upper, bb_lower, bb_width, bb_percent_b |-- calculate_ema_crossover() -> ema_9, ema_21, ema_cross_bull/bear |-- calculate_volume_features() -> volume_ratio, high_volume | |-- [jika include_ml_features=True] | calculate_ml_features() -> returns, volatility, lags, trends, time | v Output: DataFrame dengan 40+ kolom fitur ``` **Data minimum:** 26 bar (kebutuhan MACD slow EMA) agar semua fitur stabil. --- ## Kategori 1: Indikator Teknikal ### RSI (*Relative Strength Index*) -- Period 14 ``` Formula: RSI = 100 - (100 / (1 + RS)) RS = Average Gain / Average Loss Smoothing: Wilder's EMA (alpha = 1/14) ``` | Nilai | Interpretasi | |-------|-------------| | RSI > 70 | *Overbought* (potensi turun) | | RSI < 30 | *Oversold* (potensi naik) | | RSI ~ 50 | Netral | **Output:** `rsi` --- ### ATR (*Average True Range*) -- Period 14 ``` True Range = max(High-Low, |High-PrevClose|, |Low-PrevClose|) ATR = Wilder's EMA dari True Range ATR% = (ATR / Close) * 100 ``` | Kondisi | Interpretasi | |---------|-------------| | ATR tinggi | Pasar *volatile* (pergerakan besar) | | ATR rendah | Pasar tenang (pergerakan kecil) | **Output:** `atr`, `atr_percent` --- ### MACD (*Moving Average Convergence Divergence*) -- 12/26/9 ``` MACD Line = EMA(12) - EMA(26) Signal = EMA(MACD Line, 9) Histogram = MACD Line - Signal ``` | Kondisi | Interpretasi | |---------|-------------| | Histogram > 0 & naik | Bullish *momentum* menguat | | Histogram < 0 & turun | Bearish *momentum* menguat | | MACD cross Signal ke atas | Potensi reversal naik | | MACD cross Signal ke bawah | Potensi reversal turun | **Output:** `macd`, `macd_signal`, `macd_histogram` --- ### *Bollinger Bands* -- Period 20, StdDev 2.0 ``` Middle = SMA(20) Upper = Middle + 2 * StdDev Lower = Middle - 2 * StdDev Width = (Upper - Lower) / Middle %B = (Close - Lower) / (Upper - Lower) ``` | Kondisi | Interpretasi | |---------|-------------| | %B > 1 | Harga di atas upper band (extreme bullish) | | %B < 0 | Harga di bawah lower band (extreme bearish) | | %B ~ 0.5 | Harga di tengah | | Width melebar | *Volatility* meningkat | | Width menyempit | *Volatility* menurun (squeeze) | **Output:** `bb_middle`, `bb_upper`, `bb_lower`, `bb_width`, `bb_percent_b` --- ### EMA *Crossover* -- 9/21 ``` EMA9 = Exponential Moving Average (cepat) EMA21 = Exponential Moving Average (lambat) ``` *EMA* (*Exponential Moving Average*) memberikan bobot lebih besar pada data terbaru, sehingga lebih responsif terhadap perubahan harga dibanding SMA. | Kondisi | Interpretasi | |---------|-------------| | EMA9 > EMA21 | *Trend* naik | | EMA9 < EMA21 | *Trend* turun | | EMA9 cross atas EMA21 | Sinyal beli (*bullish crossover*) | | EMA9 cross bawah EMA21 | Sinyal jual (*bearish crossover*) | **Output:** `ema_9`, `ema_21`, `ema_cross_bull`, `ema_cross_bear` --- ## Kategori 2: Volume Features -- Period 20 ``` volume_sma = Rolling Mean(volume, 20) volume_ratio = volume / volume_sma volume_increasing = 1 jika volume > volume sebelumnya high_volume = 1 jika volume_ratio > 1.5 ``` **Fungsi:** Konfirmasi breakout -- pergerakan besar harus didukung volume tinggi. **Catatan:** Jika kolom volume tidak ada di data, fitur ini di-skip (graceful degradation). --- ## Kategori 3: ML-Specific Features ### *Returns* & *Momentum* ``` returns_1 = (Close[t] / Close[t-1]) - 1 # Return 1 bar returns_5 = (Close[t] / Close[t-5]) - 1 # Return 5 bar returns_20 = (Close[t] / Close[t-20]) - 1 # Return 20 bar log_returns = ln(Close[t] / Close[t-1]) # Log return ``` **Fungsi:** Mengukur kecepatan dan arah pergerakan harga (*momentum*) dalam berbagai timeframe. --- ### Price Position ``` price_position = (Close - Low) / (High - Low) # Posisi 0-1 dalam range candle dist_from_sma_20 = (Close / SMA20) - 1 # Jarak (%) dari rata-rata ``` **Fungsi:** Mengukur dimana harga relatif terhadap range dan rata-rata. --- ### *Volatility* ``` volatility_20 = StdDev(log_returns, 20) # Realized volatility normalized_range = (High - Low) / Close # Range sebagai % harga avg_normalized_range = SMA(normalized_range, 14) # Rata-rata range 14 bar ``` **Fungsi:** Input penting untuk HMM regime detection dan risk sizing. *Volatility* yang tinggi menandakan pasar bergejolak dan mempengaruhi ukuran posisi. --- ### *Lag Features* ``` close_lag_1 = Close[t-1] close_lag_2 = Close[t-2] close_lag_3 = Close[t-3] close_lag_5 = Close[t-5] ``` **Fungsi:** Auto-regressive features -- menangkap pola harga berulang. *Lag features* memberikan konteks historis langsung kepada model. --- ### *Trend* Features ``` higher_high = 1 jika High[t] > High[t-1], else 0 lower_low = 1 jika Low[t] < Low[t-1], else 0 hh_count_5 = Sum(higher_high, 5 bar) # Berapa kali HH dalam 5 bar ll_count_5 = Sum(lower_low, 5 bar) # Berapa kali LL dalam 5 bar ``` **Fungsi:** Mengukur konsistensi *trend* -- banyak HH = strong uptrend. --- ### *Time Features* ``` hour = Jam (0-23) weekday = Hari (0=Senin, 6=Minggu) london_session = 1 jika jam 08:00-16:00 UTC ny_session = 1 jika jam 13:00-21:00 UTC ``` **Fungsi:** Pasar berperilaku berbeda tiap sesi -- London *volatile*, Asian tenang. *Time features* membantu model mengenali pola berbasis waktu. **Catatan:** Hanya dihitung jika kolom `time` bertipe Datetime. --- ## Kategori 4: SMC sebagai Fitur Numerik Dari SMC Analyzer, dikonversi jadi angka untuk XGBoost: ``` swing_high = 1 / 0 swing_low = -1 / 0 fvg_signal = 1 (bull) / -1 (bear) / 0 ob = 1 (bull) / -1 (bear) / 0 bos = 1 (bull) / -1 (bear) / 0 choch = 1 (bull) / -1 (bear) / 0 market_structure = 1 (bull) / -1 (bear) / 0 regime = 0 / 1 / 2 (dari HMM) ``` --- ## Target Variable (Label Training) ```python create_target(df, lookahead=1, threshold=0.0): target = 1 jika close[t+1] > close[t] # Harga naik target = 0 jika close[t+1] <= close[t] # Harga turun/tetap target_return = close[t+1] / close[t] - 1 # Return kontinu ``` **Catatan:** Target dibuat saat training saja, tidak saat live trading. --- ## Preprocessing untuk ML ### Penanganan Null ```python # Bar awal memiliki NaN karena lookback period # Saat training: baris dengan NaN di-drop df_clean = df.select(features + [target]).drop_nulls() ``` ### Penanganan Infinity ```python # Saat prediksi: NaN & infinity diganti 0 X = np.nan_to_num(X, nan=0.0, posinf=0.0, neginf=0.0) ``` ### Normalisasi **Tidak dilakukan** -- XGBoost berbasis tree, scale-invariant (tidak perlu scaling). ### Cleanup Kolom Temporary Setiap method membersihkan kolom sementara yang diawali `_` (misal `_delta`, `_avg_gain`, dll). --- ## Fitur yang Digunakan vs Tidak ### Digunakan oleh XGBoost (24+ fitur) Semua indikator teknikal, *returns*, *volatility*, *trend*, *time features*, SMC numerik, regime. ### Tidak Digunakan (Excluded) - Kolom OHLCV asli: `time`, `open`, `high`, `low`, `close`, `volume` - Kolom meta: `spread`, `real_volume`, `target`, `target_return` - Kolom SMC level: `fvg_top`, `fvg_bottom`, `ob_top`, `ob_bottom`, dll - Kolom temporary: apapun yang diawali `_` --- ## Parameter Konfigurasi | Indikator | Parameter | Default | Configurable | |-----------|-----------|---------|-------------| | RSI (*Relative Strength Index*) | period | 14 | Ya | | ATR (*Average True Range*) | period | 14 | Ya | | MACD (*Moving Average Convergence Divergence*) | fast/slow/signal | 12/26/9 | Ya | | *Bollinger Bands* | period, std_dev | 20, 2.0 | Ya | | EMA *Crossover* | fast/slow | 9/21 | Ya | | Volume | period | 20 | Ya | | *Returns* | lookback | [1, 5, 20] | Hardcoded | | *Volatility* | window | 20 | Hardcoded | | Session | London hours | 08-16 UTC | Hardcoded | | Session | NY hours | 13-21 UTC | Hardcoded | --- ## Performa - **5000 bar features:** < 100ms (sangat cepat) - **Framework:** Pure Polars vectorized (10-100x lebih cepat dari Pandas loop) -- **bukan Pandas** - **Memory:** ~1.6MB untuk 40+ fitur x 5000 bar - **Total fitur:** 40+ kolom numerik siap ML