204 lines
5.9 KiB
Python
204 lines
5.9 KiB
Python
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def determine_signal_from_indicators(
|
|
rsi: float | None,
|
|
macd: float | None,
|
|
macd_signal: float | None,
|
|
price_vs_sma: float | None,
|
|
ema_direction: str | None,
|
|
) -> str:
|
|
bullish_signals = 0
|
|
bearish_signals = 0
|
|
total_signals = 0
|
|
|
|
if rsi is not None:
|
|
total_signals += 1
|
|
if rsi < 40:
|
|
bullish_signals += 1
|
|
elif rsi > 60:
|
|
bearish_signals += 1
|
|
|
|
if macd is not None and macd_signal is not None:
|
|
total_signals += 1
|
|
if macd > macd_signal:
|
|
bullish_signals += 1
|
|
else:
|
|
bearish_signals += 1
|
|
|
|
if price_vs_sma is not None:
|
|
total_signals += 1
|
|
if price_vs_sma > 0:
|
|
bullish_signals += 1
|
|
elif price_vs_sma < 0:
|
|
bearish_signals += 1
|
|
|
|
if ema_direction is not None:
|
|
total_signals += 1
|
|
if ema_direction == "up":
|
|
bullish_signals += 1
|
|
elif ema_direction == "down":
|
|
bearish_signals += 1
|
|
|
|
if total_signals == 0:
|
|
return "neutral"
|
|
|
|
bullish_ratio = bullish_signals / total_signals
|
|
bearish_ratio = bearish_signals / total_signals
|
|
|
|
if bullish_ratio >= 0.6:
|
|
return "bullish"
|
|
elif bearish_ratio >= 0.6:
|
|
return "bearish"
|
|
else:
|
|
return "neutral"
|
|
|
|
|
|
def calculate_timeframe_signals(
|
|
momentum_data: dict,
|
|
relative_strength_data: dict,
|
|
) -> dict:
|
|
result = {
|
|
"short_term_signal": "neutral",
|
|
"medium_term_signal": "neutral",
|
|
"long_term_signal": "neutral",
|
|
"timeframe_alignment": "neutral",
|
|
"signal_strength": 0.5,
|
|
}
|
|
|
|
try:
|
|
rsi = momentum_data.get("rsi")
|
|
macd = momentum_data.get("macd")
|
|
macd_signal = momentum_data.get("macd_signal")
|
|
ema_direction = momentum_data.get("ema10_direction")
|
|
price_vs_sma50 = momentum_data.get("price_vs_sma50")
|
|
price_vs_sma200 = momentum_data.get("price_vs_sma200")
|
|
|
|
rs_5d = relative_strength_data.get("rs_vs_spy_5d")
|
|
rs_20d = relative_strength_data.get("rs_vs_spy_20d")
|
|
rs_60d = relative_strength_data.get("rs_vs_spy_60d")
|
|
|
|
short_bullish = 0
|
|
short_bearish = 0
|
|
short_total = 0
|
|
|
|
if rsi is not None:
|
|
short_total += 1
|
|
if rsi < 35:
|
|
short_bullish += 1
|
|
elif rsi > 65:
|
|
short_bearish += 1
|
|
|
|
if ema_direction == "up":
|
|
short_total += 1
|
|
short_bullish += 1
|
|
elif ema_direction == "down":
|
|
short_total += 1
|
|
short_bearish += 1
|
|
|
|
if rs_5d is not None:
|
|
short_total += 1
|
|
if rs_5d > 0:
|
|
short_bullish += 1
|
|
elif rs_5d < 0:
|
|
short_bearish += 1
|
|
|
|
if short_total > 0:
|
|
if short_bullish / short_total >= 0.6:
|
|
result["short_term_signal"] = "bullish"
|
|
elif short_bearish / short_total >= 0.6:
|
|
result["short_term_signal"] = "bearish"
|
|
|
|
med_bullish = 0
|
|
med_bearish = 0
|
|
med_total = 0
|
|
|
|
if macd is not None and macd_signal is not None:
|
|
med_total += 1
|
|
if macd > macd_signal:
|
|
med_bullish += 1
|
|
else:
|
|
med_bearish += 1
|
|
|
|
if price_vs_sma50 is not None:
|
|
med_total += 1
|
|
if price_vs_sma50 > 0:
|
|
med_bullish += 1
|
|
elif price_vs_sma50 < -2:
|
|
med_bearish += 1
|
|
|
|
if rs_20d is not None:
|
|
med_total += 1
|
|
if rs_20d > 0:
|
|
med_bullish += 1
|
|
elif rs_20d < 0:
|
|
med_bearish += 1
|
|
|
|
if med_total > 0:
|
|
if med_bullish / med_total >= 0.6:
|
|
result["medium_term_signal"] = "bullish"
|
|
elif med_bearish / med_total >= 0.6:
|
|
result["medium_term_signal"] = "bearish"
|
|
|
|
long_bullish = 0
|
|
long_bearish = 0
|
|
long_total = 0
|
|
|
|
if price_vs_sma200 is not None:
|
|
long_total += 1
|
|
if price_vs_sma200 > 0:
|
|
long_bullish += 1
|
|
elif price_vs_sma200 < -5:
|
|
long_bearish += 1
|
|
|
|
if rs_60d is not None:
|
|
long_total += 1
|
|
if rs_60d > 0:
|
|
long_bullish += 1
|
|
elif rs_60d < 0:
|
|
long_bearish += 1
|
|
|
|
if price_vs_sma50 is not None and price_vs_sma200 is not None:
|
|
long_total += 1
|
|
if price_vs_sma50 > 0 and price_vs_sma200 > 0:
|
|
long_bullish += 1
|
|
elif price_vs_sma50 < 0 and price_vs_sma200 < 0:
|
|
long_bearish += 1
|
|
|
|
if long_total > 0:
|
|
if long_bullish / long_total >= 0.6:
|
|
result["long_term_signal"] = "bullish"
|
|
elif long_bearish / long_total >= 0.6:
|
|
result["long_term_signal"] = "bearish"
|
|
|
|
signals = [
|
|
result["short_term_signal"],
|
|
result["medium_term_signal"],
|
|
result["long_term_signal"],
|
|
]
|
|
bullish_count = signals.count("bullish")
|
|
bearish_count = signals.count("bearish")
|
|
|
|
if bullish_count == 3:
|
|
result["timeframe_alignment"] = "aligned_bullish"
|
|
result["signal_strength"] = 1.0
|
|
elif bearish_count == 3:
|
|
result["timeframe_alignment"] = "aligned_bearish"
|
|
result["signal_strength"] = 0.0
|
|
elif bullish_count >= 2:
|
|
result["timeframe_alignment"] = "mixed"
|
|
result["signal_strength"] = 0.7
|
|
elif bearish_count >= 2:
|
|
result["timeframe_alignment"] = "mixed"
|
|
result["signal_strength"] = 0.3
|
|
else:
|
|
result["timeframe_alignment"] = "neutral"
|
|
result["signal_strength"] = 0.5
|
|
|
|
except (KeyError, TypeError, ValueError) as e:
|
|
logger.warning("Failed to calculate timeframe signals: %s", str(e))
|
|
|
|
return result
|