GoshawkVortexAI commited on
Commit
7f1a5d8
·
verified ·
1 Parent(s): dd2b704

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +115 -0
  2. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+
5
+ TITLE = "AF Global Expert — Python Terminal"
6
+ DISCLAIMER = (
7
+ "Research/backtest terminal only. This is a Python reconstruction scaffold, not a "
8
+ "verified 1:1 port of the original MT4 Expert Advisor. It does not place live orders."
9
+ )
10
+
11
+ def ema(s, n):
12
+ return s.ewm(span=int(n), adjust=False).mean()
13
+
14
+ def rsi(close, n=9):
15
+ d = close.diff()
16
+ gain = d.clip(lower=0).ewm(alpha=1/n, adjust=False).mean()
17
+ loss = (-d.clip(upper=0)).ewm(alpha=1/n, adjust=False).mean()
18
+ rs = gain / loss.replace(0, np.nan)
19
+ return 100 - 100/(1+rs)
20
+
21
+ def macd(close, fast=8, slow=17, signal=9):
22
+ line = ema(close, fast) - ema(close, slow)
23
+ sig = ema(line, signal)
24
+ return line, sig
25
+
26
+ def analyze(file, symbol, lot, lot_exp, tp_pips, pip_size, macd_fast, macd_slow,
27
+ macd_signal, rsi_period, cci_period, stoch_k, stoch_d):
28
+ if file is None:
29
+ return "Upload an OHLC CSV file to begin.", None
30
+ try:
31
+ df = pd.read_csv(file.name)
32
+ df.columns = [str(c).strip().lower() for c in df.columns]
33
+ aliases = {"date":"time", "datetime":"time", "timestamp":"time",
34
+ "open":"open", "high":"high", "low":"low", "close":"close",
35
+ "volume":"volume", "tick_volume":"volume"}
36
+ df = df.rename(columns={c: aliases[c] for c in df.columns if c in aliases})
37
+ required = {"open","high","low","close"}
38
+ if not required.issubset(df.columns):
39
+ return "CSV must contain open, high, low, close columns.", None
40
+ for c in required:
41
+ df[c] = pd.to_numeric(df[c], errors="coerce")
42
+ df = df.dropna(subset=list(required)).reset_index(drop=True)
43
+ if len(df) < max(macd_slow, cci_period, stoch_k) + 5:
44
+ return "Not enough candles for the selected indicator periods.", None
45
+
46
+ close, high, low = df.close, df.high, df.low
47
+ m, ms = macd(close, macd_fast, macd_slow, macd_signal)
48
+ df["MACD"] = m
49
+ df["MACD_signal"] = ms
50
+ df["RSI"] = rsi(close, rsi_period)
51
+ tp = (high + low + close) / 3
52
+ mean = tp.rolling(cci_period).mean()
53
+ mad = tp.rolling(cci_period).apply(lambda x: np.mean(np.abs(x - np.mean(x))), raw=True)
54
+ df["CCI"] = (tp - mean) / (0.015 * mad.replace(0, np.nan))
55
+ ll = low.rolling(stoch_k).min()
56
+ hh = high.rolling(stoch_k).max()
57
+ df["Stoch_K"] = 100 * (close - ll) / (hh - ll).replace(0, np.nan)
58
+ df["Stoch_D"] = df.Stoch_K.rolling(stoch_d).mean()
59
+ df["EMA_5"] = ema(close, 5)
60
+ df["EMA_9"] = ema(close, 9)
61
+
62
+ # Transparent indicator confluence, not the EA's proprietary entry engine.
63
+ bullish = (df.MACD > df.MACD_signal) & (df.RSI > 50) & (df.EMA_5 > df.EMA_9)
64
+ bearish = (df.MACD < df.MACD_signal) & (df.RSI < 50) & (df.EMA_5 < df.EMA_9)
65
+ df["Signal"] = np.select([bullish, bearish], ["BUY", "SELL"], default="HOLD")
66
+ last = df.iloc[-1]
67
+ pip = float(pip_size)
68
+ entry = float(last.close)
69
+ tp_distance = float(tp_pips) * pip
70
+ report = (
71
+ f"## {symbol} — AF Global Python Terminal\\n"
72
+ f"**Latest close:** {entry:.8f} \\n"
73
+ f"**Signal:** {last.Signal} \\n"
74
+ f"**MACD:** {last.MACD:.6f} | **MACD signal:** {last.MACD_signal:.6f} \\n"
75
+ f"**RSI({rsi_period}):** {last.RSI:.2f} | **CCI({cci_period}):** {last.CCI:.2f} \\n"
76
+ f"**Stochastic:** %K {last.Stoch_K:.2f} / %D {last.Stoch_D:.2f} \\n"
77
+ f"**Configured lot:** {float(lot):g}; lot exponent: {float(lot_exp):g}; "
78
+ f"configured TP: {float(tp_pips):g} pips\\n\\n"
79
+ f"**Illustrative TP levels from latest close:** BUY {entry+tp_distance:.8f} / "
80
+ f"SELL {entry-tp_distance:.8f}. These are not validated order levels.\\n\\n"
81
+ f"Rows analyzed: {len(df)}. {DISCLAIMER}"
82
+ )
83
+ cols = [c for c in ["time","open","high","low","close","MACD","MACD_signal","RSI","CCI","Stoch_K","Stoch_D","Signal"] if c in df]
84
+ return report, df[cols].tail(100)
85
+ except Exception as e:
86
+ return f"Could not process file: {e}", None
87
+
88
+ with gr.Blocks(title=TITLE, theme=gr.themes.Soft()) as demo:
89
+ gr.Markdown("# AF Global Expert — Python Terminal")
90
+ gr.Markdown(DISCLAIMER)
91
+ with gr.Row():
92
+ file = gr.File(label="OHLC CSV", file_types=[".csv"])
93
+ symbol = gr.Textbox(label="Symbol", value="EURUSD")
94
+ with gr.Accordion("Strategy / risk parameters", open=True):
95
+ with gr.Row():
96
+ lot = gr.Number(label="Lots", value=0.01)
97
+ lot_exp = gr.Number(label="Lot exponent", value=1.44)
98
+ tp = gr.Number(label="Take profit (pips)", value=50)
99
+ pip = gr.Number(label="Pip size", value=0.0001)
100
+ with gr.Row():
101
+ mf = gr.Number(label="MACD fast", value=8, precision=0)
102
+ ms = gr.Number(label="MACD slow", value=17, precision=0)
103
+ msi = gr.Number(label="MACD signal", value=9, precision=0)
104
+ rp = gr.Number(label="RSI period", value=9, precision=0)
105
+ with gr.Row():
106
+ cp = gr.Number(label="CCI period", value=13, precision=0)
107
+ sk = gr.Number(label="Stochastic K", value=5, precision=0)
108
+ sd = gr.Number(label="Stochastic D", value=3, precision=0)
109
+ run = gr.Button("Analyze candles", variant="primary")
110
+ output = gr.Markdown()
111
+ table = gr.Dataframe(label="Latest candles and indicators", interactive=False)
112
+ run.click(analyze, inputs=[file,symbol,lot,lot_exp,tp,pip,mf,ms,msi,rp,cp,sk,sd],
113
+ outputs=[output,table])
114
+
115
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio>=4.44
2
+ pandas>=2.0
3
+ numpy>=1.24