GoshawkVortexAI commited on
Commit
ff0549d
·
verified ·
1 Parent(s): 901006e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -15
app.py CHANGED
@@ -35,6 +35,7 @@ VP_MODES = ["Kapalı", "Onay filtresi (POC / Value Area)", "KNN özelliği + ona
35
  GANN_MODES = ["Kapalı", "Onay filtresi (Gann Box %50)"]
36
  SMC_MODES = ["Kapalı", "Onay filtresi (SMC yapı yönü)", "Sadece SMC (yapı kırılımı girişi)"]
37
  SMC_SRC = ["Swing yapı", "Internal yapı"]
 
38
  GANN_LEVELS = [0.0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.0]
39
  GANN_FAN = [(8, "8x1"), (4, "4x1"), (3, "3x1"), (2, "2x1"), (1, "1x1"),
40
  (1/2, "1x2"), (1/3, "1x3"), (1/4, "1x4"), (1/8, "1x8")]
@@ -155,6 +156,18 @@ def ut_bot(df, key=1.0, period=10):
155
 
156
 
157
  # ------------------------------------------- Smart Money Concepts (LuxAlgo) Python portu
 
 
 
 
 
 
 
 
 
 
 
 
158
  def _smc_pivots(h, l, size):
159
  """Pine leg(size) mantığı: pivotlar `size` mum sonra doğrulanır (ileriye bakma yok).
160
  Dönüş: {doğrulama_mumu: [("H"|"L", seviye, pivot_mumu)]}"""
@@ -176,14 +189,20 @@ def _smc_pivots(h, l, size):
176
  return out
177
 
178
 
179
- def smc_analyze(df, swing_len=50, int_len=5, eq_len=3, eq_thr=0.1, ob_keep=5):
 
180
  """LuxAlgo 'Smart Money Concepts' göstergesinin Python portu: swing/internal yapı (BOS, CHoCH),
181
  order block, EQH/EQL, Fair Value Gap, premium/discount ve strong/weak high-low.
182
  Pine kaynağından birebir değil; her mum yalnızca kendisine kadarki veriyi kullanır."""
183
  n = len(df)
184
  o, h, l, c = (df[k].to_numpy(float) for k in ("Open", "High", "Low", "Close"))
185
  atr = calc_atr(df, 200).to_numpy(float)
186
- hv = (h-l) >= 2*atr # yüksek volatilite mumları: OB için high/low yer değiştirir
 
 
 
 
 
187
  ph, pl = np.where(hv, l, h), np.where(hv, h, l)
188
  swing_len = int(min(max(swing_len, 3), max(n//4, 3)))
189
  int_len = int(min(max(int_len, 2), swing_len))
@@ -198,6 +217,13 @@ def smc_analyze(df, swing_len=50, int_len=5, eq_len=3, eq_thr=0.1, ob_keep=5):
198
  st = it = 0
199
  top, bot = h[0], l[0]
200
  events, obs, points, eqs, fvgs = [], [], [], [], []
 
 
 
 
 
 
 
201
  prev_hi = prev_lo = np.nan
202
  eq_h = eq_l = None
203
  dsum = 0.0
@@ -228,15 +254,16 @@ def smc_analyze(df, swing_len=50, int_len=5, eq_len=3, eq_thr=0.1, ob_keep=5):
228
  eqs.append(("EQL", eq_l[1], eq_l[0], bi, lvl, i))
229
  eq_l = (lvl, bi)
230
  # --- order block mitigasyonu (High/Low)
231
- for ob in obs:
232
  if ob["on"] and ((ob["bull"] and l[i] < ob["lo"]) or (not ob["bull"] and h[i] > ob["hi"])):
233
  ob["on"] = False
 
234
  # --- yapı kırılımları
235
  if i > 0:
236
  for internal, hp, lp in ((True, ih, il), (False, sh, sl_)):
237
  tr = it if internal else st
238
- extra_u = (not internal) or (ih["lvl"] != sh["lvl"])
239
- extra_d = (not internal) or (il["lvl"] != sl_["lvl"])
240
  if (np.isfinite(hp["lvl"]) and not hp["crossed"] and c[i] > hp["lvl"] >= c[i-1]
241
  and extra_u):
242
  events.append({"i": i, "kind": "CHoCH" if tr == -1 else "BOS", "bull": True,
@@ -245,7 +272,7 @@ def smc_analyze(df, swing_len=50, int_len=5, eq_len=3, eq_thr=0.1, ob_keep=5):
245
  seg = pl[hp["idx"]:i]
246
  if len(seg):
247
  j = hp["idx"] + int(np.argmin(seg))
248
- obs.append({"bull": True, "internal": internal, "hi": float(ph[j]),
249
  "lo": float(pl[j]), "idx": j, "on": True})
250
  if internal:
251
  it = 1
@@ -259,7 +286,7 @@ def smc_analyze(df, swing_len=50, int_len=5, eq_len=3, eq_thr=0.1, ob_keep=5):
259
  seg = ph[lp["idx"]:i]
260
  if len(seg):
261
  j = lp["idx"] + int(np.argmax(seg))
262
- obs.append({"bull": False, "internal": internal, "hi": float(ph[j]),
263
  "lo": float(pl[j]), "idx": j, "on": True})
264
  if internal:
265
  it = -1
@@ -269,6 +296,8 @@ def smc_analyze(df, swing_len=50, int_len=5, eq_len=3, eq_thr=0.1, ob_keep=5):
269
  top, bot = max(top, h[i]), min(bot, l[i])
270
  top_a[i], bot_a[i] = top, bot
271
  swh_a[i], swl_a[i] = sh["lvl"], sl_["lvl"]
 
 
272
  # --- Fair Value Gap
273
  if i >= 2:
274
  delta = (c[i-1]-o[i-1])/(o[i-1]*100) if o[i-1] else 0.0
@@ -283,7 +312,7 @@ def smc_analyze(df, swing_len=50, int_len=5, eq_len=3, eq_thr=0.1, ob_keep=5):
283
  fvgs.append({"bull": False, "top": float(l[i-2]), "bot": float(h[i]), "idx": i-1, "on": True})
284
  live = lambda internal, bull: [o_ for o_ in obs if o_["on"] and o_["internal"] == internal
285
  and o_["bull"] == bull][-int(ob_keep):]
286
- return {"swing_trend": s_tr, "internal_trend": i_tr, "top": top_a, "bot": bot_a, "sw_hi": swh_a, "sw_lo": swl_a,
287
  "events": events, "points": points, "eq": eqs,
288
  "obs": live(True, True)+live(True, False)+live(False, True)+live(False, False),
289
  "fvg": [g for g in fvgs if g["on"]][-8:], "strong_high": st == -1, "strong_low": st == 1}
@@ -334,6 +363,16 @@ def add_smc_traces(fig, S, index, last_n=150, kw=None):
334
  textposition="top center" if kd == "H" else "bottom center",
335
  textfont=dict(size=9, color="#475569"), showlegend=False,
336
  hoverinfo="skip"), **kw)
 
 
 
 
 
 
 
 
 
 
337
  top, bot = float(S["top"][-1]), float(S["bot"][-1])
338
  if np.isfinite(top) and np.isfinite(bot) and top > bot:
339
  x0 = index[max(0, n-35)]
@@ -983,7 +1022,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
983
  ldc_use_vol, ldc_use_regime, ldc_use_adx, ldc_kernel, ldc_exact,
984
  combo_mode, combo_votes, ind_tpsl, tpsl_smin, tpsl_smax, tpsl_minrr,
985
  gann_mode, gann_lb, gann_fan_on, gann_ext_on, gann_rev,
986
- smc_mode, smc_src, smc_swing_len, smc_int_len, smc_zone, smc_draw):
 
987
  try:
988
  ticker = str(ticker).strip().upper()
989
  h = int(horizon)
@@ -1014,7 +1054,11 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
1014
  GB = gann_box(df, int(gann_lb), bool(gann_rev))
1015
  smc_on = smc_mode != SMC_MODES[0]
1016
  smc_only = smc_mode == SMC_MODES[2]
1017
- SM = smc_analyze(df, int(smc_swing_len), int(smc_int_len)) if (smc_on or smc_draw) else None
 
 
 
 
1018
  smc_arr = np.zeros(len(df), dtype=int)
1019
  if SM is not None:
1020
  smc_arr = (SM["swing_trend"] if smc_src == SMC_SRC[0] else SM["internal_trend"]).copy()
@@ -1107,10 +1151,16 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
1107
  cap_of = lambda d: np.where(d >= 1.0*a_, d, np.inf)
1108
  lv_l = [st_line, ut_stop, vpl] + ([SM["sw_lo"]] if (smc_only and SM is not None) else [])
1109
  lv_s = [st_line, ut_stop, vph] + ([SM["sw_hi"]] if (smc_only and SM is not None) else [])
 
 
 
 
 
 
1110
  A["ind_sd"] = {1: sd_of(nearest(lv_l, 1)),
1111
  -1: sd_of(nearest(lv_s, -1))}
1112
- A["ind_cap"] = {1: cap_of(nearest([vpo, vph], -1)),
1113
- -1: cap_of(nearest([vpo, vpl], 1))}
1114
 
1115
  # --- K seçimi, kalibrasyon, güncel olasılık
1116
  best_k, k_scores = tune_k(dev_X, dev_y, h)
@@ -1262,6 +1312,10 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
1262
  cands = {"Supertrend": float(st_line[-1]), "UT trailing stop": float(ut_stop[-1]),
1263
  "VP " + ("VAL" if side == 1 else "VAH"):
1264
  float((vp.val if side == 1 else vp.vah).iloc[-1])}
 
 
 
 
1265
  if smc_only and SM is not None:
1266
  cands["SMC swing " + ("low" if side == 1 else "high")] = float(SM["sw_lo" if side == 1 else "sw_hi"][-1])
1267
  valid = {k_: side*(cl_-v_) for k_, v_ in cands.items() if np.isfinite(v_) and side*(cl_-v_) > 0}
@@ -1394,9 +1448,15 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
1394
  ("Strong/Weak High · Low", f"{'Strong' if SM['strong_high'] else 'Weak'} {fmt_p(tp_)} · "
1395
  f"{'Strong' if SM['strong_low'] else 'Weak'} {fmt_p(bt_)}"),
1396
  ("Aktif swing OB (bull)", ob_txt(True)), ("Aktif swing OB (bear)", ob_txt(False)),
 
 
 
1397
  ("Açık FVG sayısı", len(SM["fvg"])), ("SMC yön onayı", dname[smc_now])])
1398
  smc_note = (f"Swing {int(smc_swing_len)} · internal {int(smc_int_len)} mum"
1399
  + (" · premium/discount kapısı açık" if smc_zone else "")
 
 
 
1400
  + (" · Mod Kapalı: yalnızca bilgi/grafik." if not smc_on else "") + ".")
1401
  else:
1402
  smc_md, smc_note = "_Mod kapalı._", ""
@@ -1439,7 +1499,7 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
1439
  tpsl_note = (f"SL: en yakın invalidasyon seviyesi — **{sl_name}** (+0,1 ATR tampon, "
1440
  f"{float(tpsl_smin):g}–{float(tpsl_smax):g} ATR aralığına sıkıştırılır). "
1441
  f"TP: {rr:.2f}R katı"
1442
- + (", önündeki Value Area/POC seviyesinde sınırlandı" if capped else "")
1443
  + ". Optimize edilen tek parametre R katıdır.\n\n")
1444
  else:
1445
  tp_title, tpsl_note = "optimize", ""
@@ -1559,7 +1619,7 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
1559
  "seri korelasyonunu ve rejim değişimini tam modellemez. Pozisyon hesabı spot miktar "
1560
  "varsayar; CFD lot sözleşmesi, spread, funding, swap, komisyon, minimum lot, marjin ve "
1561
  "broker fiyatı farklı olabilir. Gap ve kayma kaybı planlanan riskin üstüne çıkarabilir. "
1562
- "Supertrend ve UT Bot, TradingView formüllerinin Python portudur; ATR başlangıcı ve veri kaynağı yüzünden TV değerlerinden küçük sapmalar olabilir. Birleşik sinyal; ST+UT, Lorentzian ve Volume Profile oylarının birleşimidir. İndikatör bazlı TP/SL, en yakın ST/UT/VP seviyesini invalidasyon sayar ve ATR aralığına sıkıştırır. Lorentzian Classification, jdehorty'nin TradingView göstergesinin Python portudur (ANN komşu seçimi, filtreler ve kernel regresyon); Pine kaynağıyla birebir aynı sonuç vermeyebilir ve yalnızca günlük mumda çalışır. Volume Profile, günlük OHLCV'den (her mumun hacmi high–low aralığına eşit dağıtılarak) yaklaşık hesaplanır; TradingView VPVR'nin alt-zaman dilimi verisiyle birebir aynı olmaz. Gann Box, Zeiierman göstergesinin açıklamasına göre yazılmış bir Python portudur (Pine kaynağı birebir alınmadı); kutu son N mumun en yüksek/en düşük noktasından kurulur, Gann Fan 1x1 köşegeni ve katlarıyla çizilir, Gann Curves/Angles eklenmedi. Onay filtresi, kapanışın kutu %50 çizgisine göre konumuna bakar ve geçmişe bakan (kayan) pencere kullanır. SMC, LuxAlgo göstergesinin açıklamasına göre yazılmış bir Python portudur (Pine kaynağı birebir değil): swing/internal yapı, BOS/CHoCH, order block (high/low mitigasyonu), EQH/EQL, FVG ve premium/discount hesaplanır; MTF önceki high/low ve mum boyama yoktur. Sadece SMC modunda işlemler yalnızca seçilen yapıdaki (swing/internal) BOS/CHoCH kırılım mumunda, kırılım yönünde açılır; SL en yakın ST/UT/VP/SMC swing seviyesinden, TP R katından türetilir; diğer sinyal modları devre dışıdır. Pivotlar pencere kadar mum sonra doğrulanır, bu yüzden sinyal geç gelir. SMC kavramlarının istatistiksel geçerliliği kanıtlı değildir; OOS sonuçlarıyla doğrulayın. Canlı hesap öncesi paper trading ve broker bazlı doğrulama zorunludur."
1563
  )
1564
  return (report, prob_figure(p_down, p_flat, p_up), price_fig, eq_fig, pf_fig, mc_fig,
1565
  top_df, csv_path, disclaimer)
@@ -1648,6 +1708,10 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
1648
  smc_int_len = gr.Slider(3, 15, value=5, step=1, label="SMC internal yapı uzunluğu")
1649
  smc_zone = gr.Checkbox(value=False, label="Premium/Discount kapısı (long=discount, short=premium)")
1650
  smc_draw = gr.Checkbox(value=True, label="SMC katmanlarını grafikte göster")
 
 
 
 
1651
  with gr.Row():
1652
  skip_overlap = gr.Checkbox(value=False, label="Açık pozisyon varken yeni sinyali atla (tek pozisyon)")
1653
  whole_units = gr.Checkbox(value=False, label="Miktarı tam sayıya yuvarla (hisse)")
@@ -1681,7 +1745,8 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
1681
  ldc_use_vol, ldc_use_regime, ldc_use_adx, ldc_kernel, ldc_exact,
1682
  combo_mode, combo_votes, ind_tpsl, tpsl_smin, tpsl_smax, tpsl_minrr,
1683
  gann_mode, gann_lb, gann_fan_on, gann_ext_on, gann_rev,
1684
- smc_mode, smc_src, smc_swing_len, smc_int_len, smc_zone, smc_draw],
 
1685
  outputs=[output, prob_plot, chart, equity_plot, pf_plot, mc_plot, optimization,
1686
  csv_file, disclaimer],
1687
  )
 
35
  GANN_MODES = ["Kapalı", "Onay filtresi (Gann Box %50)"]
36
  SMC_MODES = ["Kapalı", "Onay filtresi (SMC yapı yönü)", "Sadece SMC (yapı kırılımı girişi)"]
37
  SMC_SRC = ["Swing yapı", "Internal yapı"]
38
+ SMC_OBF = ["Atr", "Cumulative Mean Range"]
39
  GANN_LEVELS = [0.0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.0]
40
  GANN_FAN = [(8, "8x1"), (4, "4x1"), (3, "3x1"), (2, "2x1"), (1, "1x1"),
41
  (1/2, "1x2"), (1/3, "1x3"), (1/4, "1x4"), (1/8, "1x8")]
 
156
 
157
 
158
  # ------------------------------------------- Smart Money Concepts (LuxAlgo) Python portu
159
+ def mtf_prev_levels(df):
160
+ """Önceki gün / hafta / ay high-low (tamamlanmış dönem; ileriye bakma yok), mum bazında dizi."""
161
+ out = {}
162
+ for key, rule in (("d", "D"), ("w", "W"), ("m", "M")):
163
+ per = df.index.to_period(rule)
164
+ hi = df.High.groupby(per).max().shift(1)
165
+ lo = df.Low.groupby(per).min().shift(1)
166
+ out["p"+key+"h"] = hi.reindex(per).to_numpy(float)
167
+ out["p"+key+"l"] = lo.reindex(per).to_numpy(float)
168
+ return out
169
+
170
+
171
  def _smc_pivots(h, l, size):
172
  """Pine leg(size) mantığı: pivotlar `size` mum sonra doğrulanır (ileriye bakma yok).
173
  Dönüş: {doğrulama_mumu: [("H"|"L", seviye, pivot_mumu)]}"""
 
189
  return out
190
 
191
 
192
+ def smc_analyze(df, swing_len=50, int_len=5, eq_len=3, eq_thr=0.1, ob_keep=5,
193
+ confluence=False, ob_filter="Atr"):
194
  """LuxAlgo 'Smart Money Concepts' göstergesinin Python portu: swing/internal yapı (BOS, CHoCH),
195
  order block, EQH/EQL, Fair Value Gap, premium/discount ve strong/weak high-low.
196
  Pine kaynağından birebir değil; her mum yalnızca kendisine kadarki veriyi kullanır."""
197
  n = len(df)
198
  o, h, l, c = (df[k].to_numpy(float) for k in ("Open", "High", "Low", "Close"))
199
  atr = calc_atr(df, 200).to_numpy(float)
200
+ pc_ = np.r_[c[0], c[:-1]]
201
+ tr_ = np.maximum(h-l, np.maximum(np.abs(h-pc_), np.abs(l-pc_)))
202
+ vm = (np.cumsum(tr_)/np.arange(1, n+1)) if ob_filter == "Cumulative Mean Range" else atr
203
+ hv = (h-l) >= 2*vm # yüksek volatilite mumları: OB için high/low yer değiştirir
204
+ bull_bar = (h-np.maximum(c, o)) > np.minimum(c, o-l) if confluence else np.ones(n, bool)
205
+ bear_bar = (h-np.minimum(c, o)) > np.maximum(c, o-l) if confluence else np.ones(n, bool)
206
  ph, pl = np.where(hv, l, h), np.where(hv, h, l)
207
  swing_len = int(min(max(swing_len, 3), max(n//4, 3)))
208
  int_len = int(min(max(int_len, 2), swing_len))
 
217
  st = it = 0
218
  top, bot = h[0], l[0]
219
  events, obs, points, eqs, fvgs = [], [], [], [], []
220
+ act = []
221
+ ob_sup_a, ob_res_a = np.full(n, np.nan), np.full(n, np.nan)
222
+ def _new_ob(d):
223
+ obs.append(d)
224
+ act.append(d)
225
+ if len(act) > 60:
226
+ act.pop(0)
227
  prev_hi = prev_lo = np.nan
228
  eq_h = eq_l = None
229
  dsum = 0.0
 
254
  eqs.append(("EQL", eq_l[1], eq_l[0], bi, lvl, i))
255
  eq_l = (lvl, bi)
256
  # --- order block mitigasyonu (High/Low)
257
+ for ob in act:
258
  if ob["on"] and ((ob["bull"] and l[i] < ob["lo"]) or (not ob["bull"] and h[i] > ob["hi"])):
259
  ob["on"] = False
260
+ act[:] = [o_ for o_ in act if o_["on"]]
261
  # --- yapı kırılımları
262
  if i > 0:
263
  for internal, hp, lp in ((True, ih, il), (False, sh, sl_)):
264
  tr = it if internal else st
265
+ extra_u = (not internal) or (ih["lvl"] != sh["lvl"] and bool(bull_bar[i]))
266
+ extra_d = (not internal) or (il["lvl"] != sl_["lvl"] and bool(bear_bar[i]))
267
  if (np.isfinite(hp["lvl"]) and not hp["crossed"] and c[i] > hp["lvl"] >= c[i-1]
268
  and extra_u):
269
  events.append({"i": i, "kind": "CHoCH" if tr == -1 else "BOS", "bull": True,
 
272
  seg = pl[hp["idx"]:i]
273
  if len(seg):
274
  j = hp["idx"] + int(np.argmin(seg))
275
+ _new_ob({"bull": True, "internal": internal, "hi": float(ph[j]),
276
  "lo": float(pl[j]), "idx": j, "on": True})
277
  if internal:
278
  it = 1
 
286
  seg = ph[lp["idx"]:i]
287
  if len(seg):
288
  j = lp["idx"] + int(np.argmax(seg))
289
+ _new_ob({"bull": False, "internal": internal, "hi": float(ph[j]),
290
  "lo": float(pl[j]), "idx": j, "on": True})
291
  if internal:
292
  it = -1
 
296
  top, bot = max(top, h[i]), min(bot, l[i])
297
  top_a[i], bot_a[i] = top, bot
298
  swh_a[i], swl_a[i] = sh["lvl"], sl_["lvl"]
299
+ ob_sup_a[i] = max((o_["lo"] for o_ in act if o_["bull"] and o_["lo"] < c[i]), default=np.nan)
300
+ ob_res_a[i] = min((o_["hi"] for o_ in act if (not o_["bull"]) and o_["hi"] > c[i]), default=np.nan)
301
  # --- Fair Value Gap
302
  if i >= 2:
303
  delta = (c[i-1]-o[i-1])/(o[i-1]*100) if o[i-1] else 0.0
 
312
  fvgs.append({"bull": False, "top": float(l[i-2]), "bot": float(h[i]), "idx": i-1, "on": True})
313
  live = lambda internal, bull: [o_ for o_ in obs if o_["on"] and o_["internal"] == internal
314
  and o_["bull"] == bull][-int(ob_keep):]
315
+ return {"swing_trend": s_tr, "internal_trend": i_tr, "top": top_a, "bot": bot_a, "sw_hi": swh_a, "sw_lo": swl_a, "ob_sup": ob_sup_a, "ob_res": ob_res_a, **mtf_prev_levels(df),
316
  "events": events, "points": points, "eq": eqs,
317
  "obs": live(True, True)+live(True, False)+live(False, True)+live(False, False),
318
  "fvg": [g for g in fvgs if g["on"]][-8:], "strong_high": st == -1, "strong_low": st == 1}
 
363
  textposition="top center" if kd == "H" else "bottom center",
364
  textfont=dict(size=9, color="#475569"), showlegend=False,
365
  hoverinfo="skip"), **kw)
366
+ if S.get("show_mtf"):
367
+ for k_, nm_ in (("pdh", "PDH"), ("pdl", "PDL"), ("pwh", "PWH"), ("pwl", "PWL"),
368
+ ("pmh", "PMH"), ("pml", "PML")):
369
+ y_ = S[k_][-1]
370
+ if np.isfinite(y_):
371
+ fig.add_trace(go.Scatter(x=[index[w0], index[-1]], y=[y_, y_], mode="lines+text",
372
+ text=["", nm_], textposition="top left",
373
+ line=dict(width=1, dash="dashdot", color="#0ea5e9"),
374
+ textfont=dict(size=9, color="#0ea5e9"), showlegend=False,
375
+ hoverinfo="skip"), **kw)
376
  top, bot = float(S["top"][-1]), float(S["bot"][-1])
377
  if np.isfinite(top) and np.isfinite(bot) and top > bot:
378
  x0 = index[max(0, n-35)]
 
1022
  ldc_use_vol, ldc_use_regime, ldc_use_adx, ldc_kernel, ldc_exact,
1023
  combo_mode, combo_votes, ind_tpsl, tpsl_smin, tpsl_smax, tpsl_minrr,
1024
  gann_mode, gann_lb, gann_fan_on, gann_ext_on, gann_rev,
1025
+ smc_mode, smc_src, smc_swing_len, smc_int_len, smc_zone, smc_draw,
1026
+ smc_conf, smc_obf, smc_lvl):
1027
  try:
1028
  ticker = str(ticker).strip().upper()
1029
  h = int(horizon)
 
1054
  GB = gann_box(df, int(gann_lb), bool(gann_rev))
1055
  smc_on = smc_mode != SMC_MODES[0]
1056
  smc_only = smc_mode == SMC_MODES[2]
1057
+ SM = smc_analyze(df, int(smc_swing_len), int(smc_int_len), confluence=bool(smc_conf),
1058
+ ob_filter=smc_obf) if (smc_on or smc_draw) else None
1059
+ smc_lvl_on = bool(smc_lvl) and SM is not None and smc_on
1060
+ if SM is not None:
1061
+ SM["show_mtf"] = bool(smc_lvl)
1062
  smc_arr = np.zeros(len(df), dtype=int)
1063
  if SM is not None:
1064
  smc_arr = (SM["swing_trend"] if smc_src == SMC_SRC[0] else SM["internal_trend"]).copy()
 
1151
  cap_of = lambda d: np.where(d >= 1.0*a_, d, np.inf)
1152
  lv_l = [st_line, ut_stop, vpl] + ([SM["sw_lo"]] if (smc_only and SM is not None) else [])
1153
  lv_s = [st_line, ut_stop, vph] + ([SM["sw_hi"]] if (smc_only and SM is not None) else [])
1154
+ cap_l, cap_s = [vpo, vph], [vpo, vpl]
1155
+ if smc_lvl_on: # Order Block + önceki D/W/M high-low: SL referansı ve TP sınırı
1156
+ lv_l += [SM["ob_sup"], SM["pdl"], SM["pwl"], SM["pml"]]
1157
+ lv_s += [SM["ob_res"], SM["pdh"], SM["pwh"], SM["pmh"]]
1158
+ cap_l += [SM["ob_res"], SM["pdh"], SM["pwh"], SM["pmh"]]
1159
+ cap_s += [SM["ob_sup"], SM["pdl"], SM["pwl"], SM["pml"]]
1160
  A["ind_sd"] = {1: sd_of(nearest(lv_l, 1)),
1161
  -1: sd_of(nearest(lv_s, -1))}
1162
+ A["ind_cap"] = {1: cap_of(nearest(cap_l, -1)),
1163
+ -1: cap_of(nearest(cap_s, 1))}
1164
 
1165
  # --- K seçimi, kalibrasyon, güncel olasılık
1166
  best_k, k_scores = tune_k(dev_X, dev_y, h)
 
1312
  cands = {"Supertrend": float(st_line[-1]), "UT trailing stop": float(ut_stop[-1]),
1313
  "VP " + ("VAL" if side == 1 else "VAH"):
1314
  float((vp.val if side == 1 else vp.vah).iloc[-1])}
1315
+ if smc_lvl_on:
1316
+ kk_ = ("ob_sup", "pdl", "pwl", "pml") if side == 1 else ("ob_res", "pdh", "pwh", "pmh")
1317
+ for k_, nm_ in zip(kk_, ("SMC OB", "Önceki gün", "Önceki hafta", "Önceki ay")):
1318
+ cands[nm_] = float(SM[k_][-1])
1319
  if smc_only and SM is not None:
1320
  cands["SMC swing " + ("low" if side == 1 else "high")] = float(SM["sw_lo" if side == 1 else "sw_hi"][-1])
1321
  valid = {k_: side*(cl_-v_) for k_, v_ in cands.items() if np.isfinite(v_) and side*(cl_-v_) > 0}
 
1448
  ("Strong/Weak High · Low", f"{'Strong' if SM['strong_high'] else 'Weak'} {fmt_p(tp_)} · "
1449
  f"{'Strong' if SM['strong_low'] else 'Weak'} {fmt_p(bt_)}"),
1450
  ("Aktif swing OB (bull)", ob_txt(True)), ("Aktif swing OB (bear)", ob_txt(False)),
1451
+ ("Önceki gün H / L", f"{fmt_p(SM['pdh'][-1])} / {fmt_p(SM['pdl'][-1])}"),
1452
+ ("Önceki hafta H / L", f"{fmt_p(SM['pwh'][-1])} / {fmt_p(SM['pwl'][-1])}"),
1453
+ ("Önceki ay H / L", f"{fmt_p(SM['pmh'][-1])} / {fmt_p(SM['pml'][-1])}"),
1454
  ("Açık FVG sayısı", len(SM["fvg"])), ("SMC yön onayı", dname[smc_now])])
1455
  smc_note = (f"Swing {int(smc_swing_len)} · internal {int(smc_int_len)} mum"
1456
  + (" · premium/discount kapısı açık" if smc_zone else "")
1457
+ + (" · internal confluence filtresi" if smc_conf else "")
1458
+ + f" · OB filtresi: {smc_obf}"
1459
+ + (" · OB + önceki D/W/M seviyeleri SL/TP'de" if smc_lvl_on else "")
1460
  + (" · Mod Kapalı: yalnızca bilgi/grafik." if not smc_on else "") + ".")
1461
  else:
1462
  smc_md, smc_note = "_Mod kapalı._", ""
 
1499
  tpsl_note = (f"SL: en yakın invalidasyon seviyesi — **{sl_name}** (+0,1 ATR tampon, "
1500
  f"{float(tpsl_smin):g}–{float(tpsl_smax):g} ATR aralığına sıkıştırılır). "
1501
  f"TP: {rr:.2f}R katı"
1502
+ + (", önündeki VA/POC/SMC OB/MTF seviyesinde sınırlandı" if capped else "")
1503
  + ". Optimize edilen tek parametre R katıdır.\n\n")
1504
  else:
1505
  tp_title, tpsl_note = "optimize", ""
 
1619
  "seri korelasyonunu ve rejim değişimini tam modellemez. Pozisyon hesabı spot miktar "
1620
  "varsayar; CFD lot sözleşmesi, spread, funding, swap, komisyon, minimum lot, marjin ve "
1621
  "broker fiyatı farklı olabilir. Gap ve kayma kaybı planlanan riskin üstüne çıkarabilir. "
1622
+ "Supertrend ve UT Bot, TradingView formüllerinin Python portudur; ATR başlangıcı ve veri kaynağı yüzünden TV değerlerinden küçük sapmalar olabilir. Birleşik sinyal; ST+UT, Lorentzian ve Volume Profile oylarının birleşimidir. İndikatör bazlı TP/SL, en yakın ST/UT/VP seviyesini invalidasyon sayar ve ATR aralığına sıkıştırır. Lorentzian Classification, jdehorty'nin TradingView göstergesinin Python portudur (ANN komşu seçimi, filtreler ve kernel regresyon); Pine kaynağıyla birebir aynı sonuç vermeyebilir ve yalnızca günlük mumda çalışır. Volume Profile, günlük OHLCV'den (her mumun hacmi high–low aralığına eşit dağıtılarak) yaklaşık hesaplanır; TradingView VPVR'nin alt-zaman dilimi verisiyle birebir aynı olmaz. Gann Box, Zeiierman göstergesinin açıklamasına göre yazılmış bir Python portudur (Pine kaynağı birebir alınmadı); kutu son N mumun en yüksek/en düşük noktasından kurulur, Gann Fan 1x1 köşegeni ve katlarıyla çizilir, Gann Curves/Angles eklenmedi. Onay filtresi, kapanışın kutu %50 çizgisine göre konumuna bakar ve geçmişe bakan (kayan) pencere kullanır. SMC, LuxAlgo göstergesinin açıklamasına göre yazılmış bir Python portudur (Pine kaynağı birebir değil): swing/internal yapı, BOS/CHoCH, order block (high/low mitigasyonu), EQH/EQL, FVG ve premium/discount hesaplanır; mum boyama yoktur; internal confluence ve OB filtresi, Pine formüllerinin hafızadan yazılmış karşılığıdır. OB ve önceki gün/hafta/ay high-low seviyeleri, «TP/SL'i indikatörlerden türet» açıkken en yakın seviye SL referansı ve TP sınırı olarak backtest'e girer. Sadece SMC modunda işlemler yalnızca seçilen yapıdaki (swing/internal) BOS/CHoCH kırılım mumunda, kırılım yönünde açılır; SL en yakın ST/UT/VP/SMC swing seviyesinden, TP R katından türetilir; diğer sinyal modları devre dışıdır. Pivotlar pencere kadar mum sonra doğrulanır, bu yüzden sinyal geç gelir. SMC kavramlarının istatistiksel geçerliliği kanıtlı değildir; OOS sonuçlarıyla doğrulayın. Canlı hesap öncesi paper trading ve broker bazlı doğrulama zorunludur."
1623
  )
1624
  return (report, prob_figure(p_down, p_flat, p_up), price_fig, eq_fig, pf_fig, mc_fig,
1625
  top_df, csv_path, disclaimer)
 
1708
  smc_int_len = gr.Slider(3, 15, value=5, step=1, label="SMC internal yapı uzunluğu")
1709
  smc_zone = gr.Checkbox(value=False, label="Premium/Discount kapısı (long=discount, short=premium)")
1710
  smc_draw = gr.Checkbox(value=True, label="SMC katmanlarını grafikte göster")
1711
+ with gr.Row():
1712
+ smc_conf = gr.Checkbox(value=False, label="Internal confluence filtresi (zayıf kırılımları ele)")
1713
+ smc_obf = gr.Radio(SMC_OBF, value=SMC_OBF[0], label="Order Block volatilite filtresi")
1714
+ smc_lvl = gr.Checkbox(value=True, label="SMC seviyeleri TP/SL'de kullan (Order Block + önceki gün/hafta/ay H-L)")
1715
  with gr.Row():
1716
  skip_overlap = gr.Checkbox(value=False, label="Açık pozisyon varken yeni sinyali atla (tek pozisyon)")
1717
  whole_units = gr.Checkbox(value=False, label="Miktarı tam sayıya yuvarla (hisse)")
 
1745
  ldc_use_vol, ldc_use_regime, ldc_use_adx, ldc_kernel, ldc_exact,
1746
  combo_mode, combo_votes, ind_tpsl, tpsl_smin, tpsl_smax, tpsl_minrr,
1747
  gann_mode, gann_lb, gann_fan_on, gann_ext_on, gann_rev,
1748
+ smc_mode, smc_src, smc_swing_len, smc_int_len, smc_zone, smc_draw,
1749
+ smc_conf, smc_obf, smc_lvl],
1750
  outputs=[output, prob_plot, chart, equity_plot, pf_plot, mc_plot, optimization,
1751
  csv_file, disclaimer],
1752
  )