GoshawkVortexAI commited on
Commit
63ce4cc
·
verified ·
1 Parent(s): f1f59b0

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +117 -0
  2. requirements.txt +4 -0
app.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import yfinance as yf
3
+ import pandas as pd
4
+ import numpy as np
5
+
6
+ def ema(s, n):
7
+ return s.ewm(span=int(n), adjust=False).mean()
8
+
9
+ def rsi(s, n=9):
10
+ d=s.diff()
11
+ up=d.clip(lower=0).ewm(alpha=1/n, adjust=False).mean()
12
+ dn=(-d.clip(upper=0)).ewm(alpha=1/n, adjust=False).mean()
13
+ rs=up/dn.replace(0,np.nan)
14
+ return 100-100/(1+rs)
15
+
16
+ def load_data(ticker, period, interval):
17
+ df=yf.download(ticker,period=period,interval=interval,auto_adjust=False,progress=False,threads=False)
18
+ if df is None or df.empty: return None
19
+ if isinstance(df.columns,pd.MultiIndex): df.columns=df.columns.get_level_values(0)
20
+ df.columns=[str(c).title() for c in df.columns]
21
+ needed=["Open","High","Low","Close"]
22
+ if not set(needed).issubset(df.columns): return None
23
+ return df.dropna(subset=needed).copy()
24
+
25
+ def build_signals(df, fast, slow, sig, rsi_len, fee_pct, slippage_pct):
26
+ c=df["Close"]
27
+ macd=ema(c,fast)-ema(c,slow)
28
+ macd_sig=ema(macd,sig)
29
+ rs=rsi(c,rsi_len)
30
+ e5,e9=ema(c,5),ema(c,9)
31
+ buy=(macd>macd_sig)&(rs>50)&(e5>e9)
32
+ sell=(macd<macd_sig)&(rs<50)&(e5<e9)
33
+ # Avoid look-ahead: signal on close, enter at next bar open.
34
+ raw=np.select([buy,sell],[1,-1],default=0)
35
+ pos=pd.Series(raw,index=df.index).shift(1).fillna(0)
36
+ # Position changes close previous position and open new one at current open.
37
+ open_px=df["Open"].astype(float)
38
+ close_px=c.astype(float)
39
+ ret=close_px.pct_change().fillna(0)
40
+ # Approximate bar return while holding prior signal; fee/slippage charged on position changes.
41
+ strat=pos*ret
42
+ changes=pos.diff().abs().fillna(pos.abs())
43
+ costs=changes*(float(fee_pct)+float(slippage_pct))/100
44
+ net=strat-costs
45
+ equity=(1+net).cumprod()
46
+ return pos, net, equity, macd, macd_sig, rs, changes
47
+
48
+ def backtest(ticker, interval, period, initial, fast, slow, sig, rsi_len, fee, slip):
49
+ try:
50
+ df=load_data(ticker.strip(),period,interval)
51
+ if df is None or len(df)<max(int(slow),int(rsi_len))+10:
52
+ return "Veri alınamadı veya yeterli mum yok. Sembol ve periyodu kontrol edin.",None
53
+ pos, net, equity, macd, ms, rs, changes=build_signals(df,int(fast),int(slow),int(sig),int(rsi_len),float(fee),float(slip))
54
+ # Trades are contiguous non-flat position runs. Approximate trade stats from bar returns.
55
+ active=pos.ne(0)
56
+ starts=active & ~active.shift(1,fill_value=False)
57
+ ends=active & ~active.shift(-1,fill_value=False)
58
+ trade_returns=[]
59
+ for start_idx in np.flatnonzero(starts.to_numpy()):
60
+ end_candidates=np.flatnonzero(ends.to_numpy()[start_idx:])
61
+ if len(end_candidates)==0: continue
62
+ end_idx=start_idx+end_candidates[0]
63
+ trade_returns.append(float((1+net.iloc[start_idx:end_idx+1]).prod()-1))
64
+ trades=np.array(trade_returns,dtype=float)
65
+ wins=int((trades>0).sum())
66
+ win_rate=100*wins/len(trades) if len(trades) else 0
67
+ total_return=float(equity.iloc[-1]-1)
68
+ peak=equity.cummax()
69
+ dd=equity/peak-1
70
+ max_dd=float(dd.min())
71
+ gross_profit=float(trades[trades>0].sum()) if len(trades) else 0
72
+ gross_loss=float(-trades[trades<0].sum()) if len(trades) else 0
73
+ pf=gross_profit/gross_loss if gross_loss>0 else (float("inf") if gross_profit>0 else 0)
74
+ final=float(initial)*(1+total_return)
75
+ report=(f"## {ticker} — Backtest sonuçları\\n"
76
+ f"- **İşlem sayısı:** {len(trades)}\\n"
77
+ f"- **Kazanma oranı:** {win_rate:.2f}%\\n"
78
+ f"- **Net getiri:** {total_return*100:.2f}%\\n"
79
+ f"- **Başlangıç bakiyesi:** {float(initial):,.2f}\\n"
80
+ f"- **Teorik bitiş bakiyesi:** {final:,.2f}\\n"
81
+ f"- **Maksimum düşüş (equity):** {max_dd*100:.2f}%\\n"
82
+ f"- **Profit factor (işlem getirilerinden yaklaşık):** {pf:.2f}\\n\\n"
83
+ f"**Not:** Bu, MACD/RSI/EMA örnek stratejisinin yaklaşık backtestidir; MT4 EA'nın birebir portu değildir. "
84
+ f"Yahoo Finance verileri, spread/komisyon ve kayma varsayımları sonuçları etkiler. "
85
+ f"Pozisyonlar kapanıştan sonraki mumda açılacak şekilde geciktirilmiştir; emir icrası ve lot artırma EA mantığı modellenmemiştir.")
86
+ out=df.copy()
87
+ out["MACD"]=macd; out["MACD_signal"]=ms; out[f"RSI_{int(rsi_len)}"]=rs
88
+ out["Position"]=pos.map({1:"LONG",-1:"SHORT",0:"FLAT"})
89
+ out["Strategy_return_%"]=net*100
90
+ out["Equity"]=float(initial)*equity
91
+ out["Drawdown_%"]=dd*100
92
+ out=out.reset_index().tail(500)
93
+ return report,out
94
+ except Exception as e:
95
+ return f"Backtest hatası: {e}",None
96
+
97
+ with gr.Blocks(title="AF Global Backtest Terminal",theme=gr.themes.Soft()) as demo:
98
+ gr.Markdown("# AF Global Expert — YFinance Backtest")
99
+ gr.Markdown("E-posta gönderimi yoktur. Veriler Yahoo Finance'tan çekilir. Strateji, örnek MACD/RSI/EMA birleşimidir; orijinal EA'nın birebir dönüşümü değildir.")
100
+ with gr.Row():
101
+ ticker=gr.Textbox(label="Yahoo sembolü",value="EURUSD=X")
102
+ interval=gr.Dropdown(["5m","15m","30m","60m","1h","1d","1wk"],value="1h",label="Zaman dilimi")
103
+ period=gr.Dropdown(["5d","1mo","3mo","6mo","1y","2y","5y"],value="1y",label="Geçmiş")
104
+ with gr.Row():
105
+ initial=gr.Number(label="Başlangıç bakiyesi",value=10000)
106
+ fee=gr.Number(label="Komisyon (%) / pozisyon değişimi",value=0.02)
107
+ slip=gr.Number(label="Kayma (%) / pozisyon değişimi",value=0.01)
108
+ with gr.Row():
109
+ fast=gr.Number(label="MACD fast",value=8,precision=0)
110
+ slow=gr.Number(label="MACD slow",value=17,precision=0)
111
+ sig=gr.Number(label="MACD signal",value=9,precision=0)
112
+ rsi_len=gr.Number(label="RSI period",value=9,precision=0)
113
+ btn=gr.Button("Veriyi çek ve backtest yap",variant="primary")
114
+ report=gr.Markdown()
115
+ table=gr.Dataframe(label="Son 500 mum — sinyal, getiri ve equity",interactive=False)
116
+ btn.click(backtest,[ticker,interval,period,initial,fast,slow,sig,rsi_len,fee,slip],[report,table])
117
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio>=4.44
2
+ yfinance>=0.2.65
3
+ pandas>=2.0
4
+ numpy>=1.24