refactor(common): rename package option_mcp_common → mcp_common
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def sma(values: list[float], period: int) -> float | None:
|
||||
if len(values) < period:
|
||||
return None
|
||||
return sum(values[-period:]) / period
|
||||
|
||||
|
||||
def rsi(closes: list[float], period: int = 14) -> float | None:
|
||||
if len(closes) < period + 1:
|
||||
return None
|
||||
gains: list[float] = []
|
||||
losses: list[float] = []
|
||||
for i in range(1, len(closes)):
|
||||
delta = closes[i] - closes[i - 1]
|
||||
gains.append(max(delta, 0.0))
|
||||
losses.append(-min(delta, 0.0))
|
||||
avg_gain = sum(gains[:period]) / period
|
||||
avg_loss = sum(losses[:period]) / period
|
||||
for i in range(period, len(gains)):
|
||||
avg_gain = (avg_gain * (period - 1) + gains[i]) / period
|
||||
avg_loss = (avg_loss * (period - 1) + losses[i]) / period
|
||||
if avg_loss == 0:
|
||||
return 100.0
|
||||
rs = avg_gain / avg_loss
|
||||
return 100.0 - (100.0 / (1.0 + rs))
|
||||
|
||||
|
||||
def _ema_series(values: list[float], period: int) -> list[float]:
|
||||
if len(values) < period:
|
||||
return []
|
||||
k = 2.0 / (period + 1)
|
||||
seed = sum(values[:period]) / period
|
||||
out = [seed]
|
||||
for v in values[period:]:
|
||||
out.append(out[-1] + k * (v - out[-1]))
|
||||
return out
|
||||
|
||||
|
||||
def macd(
|
||||
closes: list[float],
|
||||
fast: int = 12,
|
||||
slow: int = 26,
|
||||
signal: int = 9,
|
||||
) -> dict[str, float | None]:
|
||||
nothing: dict[str, float | None] = {"macd": None, "signal": None, "hist": None}
|
||||
if len(closes) < slow + signal:
|
||||
return nothing
|
||||
ema_fast = _ema_series(closes, fast)
|
||||
ema_slow = _ema_series(closes, slow)
|
||||
offset = slow - fast
|
||||
aligned_fast = ema_fast[offset:]
|
||||
macd_line = [f - s for f, s in zip(aligned_fast, ema_slow, strict=False)]
|
||||
if len(macd_line) < signal:
|
||||
return nothing
|
||||
signal_line = _ema_series(macd_line, signal)
|
||||
if not signal_line:
|
||||
return nothing
|
||||
last_macd = macd_line[-1]
|
||||
last_sig = signal_line[-1]
|
||||
return {
|
||||
"macd": last_macd,
|
||||
"signal": last_sig,
|
||||
"hist": last_macd - last_sig,
|
||||
}
|
||||
|
||||
|
||||
def atr(
|
||||
highs: list[float],
|
||||
lows: list[float],
|
||||
closes: list[float],
|
||||
period: int = 14,
|
||||
) -> float | None:
|
||||
if len(closes) < period + 1:
|
||||
return None
|
||||
trs: list[float] = []
|
||||
for i in range(1, len(closes)):
|
||||
tr = max(
|
||||
highs[i] - lows[i],
|
||||
abs(highs[i] - closes[i - 1]),
|
||||
abs(lows[i] - closes[i - 1]),
|
||||
)
|
||||
trs.append(tr)
|
||||
if len(trs) < period:
|
||||
return None
|
||||
avg = sum(trs[:period]) / period
|
||||
for i in range(period, len(trs)):
|
||||
avg = (avg * (period - 1) + trs[i]) / period
|
||||
return avg
|
||||
|
||||
|
||||
def adx(
|
||||
highs: list[float],
|
||||
lows: list[float],
|
||||
closes: list[float],
|
||||
period: int = 14,
|
||||
) -> dict[str, float | None]:
|
||||
nothing: dict[str, float | None] = {"adx": None, "+di": None, "-di": None}
|
||||
if len(closes) < 2 * period + 1:
|
||||
return nothing
|
||||
trs: list[float] = []
|
||||
plus_dms: list[float] = []
|
||||
minus_dms: list[float] = []
|
||||
for i in range(1, len(closes)):
|
||||
tr = max(
|
||||
highs[i] - lows[i],
|
||||
abs(highs[i] - closes[i - 1]),
|
||||
abs(lows[i] - closes[i - 1]),
|
||||
)
|
||||
up = highs[i] - highs[i - 1]
|
||||
dn = lows[i - 1] - lows[i]
|
||||
plus_dm = up if (up > dn and up > 0) else 0.0
|
||||
minus_dm = dn if (dn > up and dn > 0) else 0.0
|
||||
trs.append(tr)
|
||||
plus_dms.append(plus_dm)
|
||||
minus_dms.append(minus_dm)
|
||||
|
||||
atr_s = sum(trs[:period])
|
||||
pdm_s = sum(plus_dms[:period])
|
||||
mdm_s = sum(minus_dms[:period])
|
||||
dxs: list[float] = []
|
||||
pdi = mdi = 0.0
|
||||
for i in range(period, len(trs)):
|
||||
atr_s = atr_s - atr_s / period + trs[i]
|
||||
pdm_s = pdm_s - pdm_s / period + plus_dms[i]
|
||||
mdm_s = mdm_s - mdm_s / period + minus_dms[i]
|
||||
pdi = 100.0 * pdm_s / atr_s if atr_s else 0.0
|
||||
mdi = 100.0 * mdm_s / atr_s if atr_s else 0.0
|
||||
s = pdi + mdi
|
||||
dx = 100.0 * abs(pdi - mdi) / s if s else 0.0
|
||||
dxs.append(dx)
|
||||
|
||||
if len(dxs) < period:
|
||||
return nothing
|
||||
adx_val = sum(dxs[:period]) / period
|
||||
for i in range(period, len(dxs)):
|
||||
adx_val = (adx_val * (period - 1) + dxs[i]) / period
|
||||
return {"adx": adx_val, "+di": pdi, "-di": mdi}
|
||||
Reference in New Issue
Block a user