mirror of
https://github.com/quachtinh113/main-fx.git
synced 2026-08-21 22:58:25 +00:00
rsi update
This commit is contained in:
@@ -0,0 +1,88 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
import pandas as pd
|
||||||
|
import pandas_ta as ta
|
||||||
|
|
||||||
|
class RSIMultiTimeframe:
|
||||||
|
def __init__(self, rsi_period: int = 14, low: float = 30, high: float = 70, mid: float = 50):
|
||||||
|
self.rsi_period = rsi_period
|
||||||
|
self.low = low
|
||||||
|
self.high = high
|
||||||
|
self.mid = mid
|
||||||
|
|
||||||
|
def compute_rsi(self, df: pd.DataFrame, tf_name: str) -> pd.Series:
|
||||||
|
# Trả về Series để tiết kiệm bộ nhớ thay vì DataFrame
|
||||||
|
return ta.rsi(df["close"], length=self.rsi_period).rename(f"rsi_{tf_name}")
|
||||||
|
|
||||||
|
def align_timeframes(
|
||||||
|
self,
|
||||||
|
df_m15: pd.DataFrame,
|
||||||
|
df_h1: pd.DataFrame,
|
||||||
|
df_h4: pd.DataFrame,
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
# Sắp xếp index để merge_asof hoạt động chính xác
|
||||||
|
df_m15 = df_m15.sort_index()
|
||||||
|
|
||||||
|
# TÍNH RSI VÀ SHIFT 1 NẾN:
|
||||||
|
# Việc shift(1) đảm bảo M15 chỉ sử dụng RSI của nến H1/H4 ĐÃ ĐÓNG HOÀN TOÀN
|
||||||
|
rsi_h1 = self.compute_rsi(df_h1, "h1").shift(1)
|
||||||
|
rsi_h4 = self.compute_rsi(df_h4, "h4").shift(1)
|
||||||
|
rsi_m15 = self.compute_rsi(df_m15, "m15") # M15 không shift vì ta coi như trigger tại giá đóng nến M15
|
||||||
|
|
||||||
|
# Merge H1
|
||||||
|
df = pd.merge_asof(
|
||||||
|
df_m15,
|
||||||
|
rsi_h1,
|
||||||
|
left_index=True,
|
||||||
|
right_index=True,
|
||||||
|
direction="backward",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Merge H4
|
||||||
|
df = pd.merge_asof(
|
||||||
|
df,
|
||||||
|
rsi_h4,
|
||||||
|
left_index=True,
|
||||||
|
right_index=True,
|
||||||
|
direction="backward",
|
||||||
|
)
|
||||||
|
|
||||||
|
df["rsi_m15"] = rsi_m15
|
||||||
|
|
||||||
|
# Bỏ qua các nến đầu tiên bị NaN do chưa đủ chu kỳ RSI
|
||||||
|
return df.dropna(subset=["rsi_h4", "rsi_h1", "rsi_m15"])
|
||||||
|
|
||||||
|
def classify(self, df: pd.DataFrame) -> pd.DataFrame:
|
||||||
|
df = df.copy()
|
||||||
|
|
||||||
|
# Thêm vùng đệm (Buffer) 52/48 để tránh nhiễu tại vùng 50
|
||||||
|
df["trend"] = 0
|
||||||
|
df.loc[df["rsi_h4"] > 52, "trend"] = 1
|
||||||
|
df.loc[df["rsi_h4"] < 48, "trend"] = -1
|
||||||
|
|
||||||
|
df["bias"] = 0
|
||||||
|
df.loc[df["rsi_h1"] > 50, "bias"] = 1
|
||||||
|
df.loc[df["rsi_h1"] < 50, "bias"] = -1
|
||||||
|
|
||||||
|
# TRIGGER (M15) - Giữ nguyên logic Reversal của bạn vì nó rất tốt
|
||||||
|
df["rsi_prev"] = df["rsi_m15"].shift(1)
|
||||||
|
df["trigger_buy"] = (df["rsi_prev"] < self.low) & (df["rsi_m15"] >= self.low)
|
||||||
|
df["trigger_sell"] = (df["rsi_prev"] > self.high) & (df["rsi_m15"] <= self.high)
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def generate_signal(self, df: pd.DataFrame) -> pd.DataFrame:
|
||||||
|
df["signal"] = 0
|
||||||
|
# Mua khi: H4 Trend tăng + H1 Bias tăng + M15 RSI cắt lên từ vùng Oversold
|
||||||
|
buy_cond = (df["trend"] == 1) & (df["bias"] == 1) & df["trigger_buy"]
|
||||||
|
# Bán khi: H4 Trend giảm + H1 Bias giảm + M15 RSI cắt xuống từ vùng Overbought
|
||||||
|
sell_cond = (df["trend"] == -1) & (df["bias"] == -1) & df["trigger_sell"]
|
||||||
|
|
||||||
|
df.loc[buy_cond, "signal"] = 1
|
||||||
|
df.loc[sell_cond, "signal"] = -1
|
||||||
|
return df
|
||||||
|
|
||||||
|
def run(self, df_m15: pd.DataFrame, df_h1: pd.DataFrame, df_h4: pd.DataFrame) -> pd.DataFrame:
|
||||||
|
df = self.align_timeframes(df_m15, df_h1, df_h4)
|
||||||
|
df = self.classify(df)
|
||||||
|
df = self.generate_signal(df)
|
||||||
|
return df
|
||||||
Reference in New Issue
Block a user