52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
"""ATR Wilder smoothing + entry/stop/target 계산."""
|
|
|
|
import pandas as pd
|
|
|
|
|
|
def compute_atr_wilder(df_one_ticker: pd.DataFrame, window: int = 14) -> float:
|
|
"""단일 종목 DataFrame(date·open·high·low·close)에 대해 Wilder ATR 마지막 값."""
|
|
g = df_one_ticker.sort_values("date").copy()
|
|
high = g["high"].astype(float)
|
|
low = g["low"].astype(float)
|
|
close = g["close"].astype(float)
|
|
prev_close = close.shift(1)
|
|
tr = pd.concat([
|
|
(high - low),
|
|
(high - prev_close).abs(),
|
|
(low - prev_close).abs(),
|
|
], axis=1).max(axis=1)
|
|
atr = tr.ewm(alpha=1 / window, adjust=False).mean()
|
|
return float(atr.iloc[-1])
|
|
|
|
|
|
def round_won(x: float) -> int:
|
|
return int(round(x))
|
|
|
|
|
|
def plan_positions(ctx, tickers: list, params: dict) -> dict:
|
|
"""각 ticker 에 대해 entry/stop/target/atr14 반환."""
|
|
atr_window = int(params.get("atr_window", 14))
|
|
stop_mult = float(params.get("atr_stop_mult", 2.0))
|
|
rr = float(params.get("rr_ratio", 2.0))
|
|
|
|
prices = ctx.prices.sort_values("date")
|
|
out: dict = {}
|
|
for t in tickers:
|
|
sub = prices[prices["ticker"] == t]
|
|
if sub.empty:
|
|
continue
|
|
close = float(sub["close"].iloc[-1])
|
|
atr14 = compute_atr_wilder(sub, window=atr_window)
|
|
entry = round_won(close * 1.005)
|
|
stop = round_won(close - stop_mult * atr14)
|
|
target = round_won(entry + rr * (entry - stop))
|
|
r_pct = (entry - stop) / entry * 100 if entry else 0.0
|
|
out[t] = {
|
|
"entry_price": entry,
|
|
"stop_price": stop,
|
|
"target_price": target,
|
|
"atr14": atr14,
|
|
"r_pct": r_pct,
|
|
}
|
|
return out
|