Spaces:
Sleeping
Sleeping
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # JULIA STRATEGY TEMPLATE | |
| # This is the exact format Claude generates for each strategy. | |
| # Two functions required. No module/using declarations needed β | |
| # all Indicators functions are pre-injected by SignalCompiler.jl. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # ββ Example: EMA Crossover Strategy βββββββββββββββββββββββββββββββββ | |
| """ | |
| Return parameter ranges for walk-forward grid search. | |
| Keys must be valid Julia identifiers. Values are Float64 ranges. | |
| """ | |
| function get_param_grid() :: Dict{String, Vector{Float64}} | |
| return Dict( | |
| "fast_period" => [10.0, 15.0, 20.0, 25.0], | |
| "slow_period" => [40.0, 50.0, 60.0, 80.0], | |
| "atr_filter" => [14.0], # single value = no optimization | |
| ) | |
| end | |
| """ | |
| Generate trading signals from OHLCV arrays. | |
| Arguments (all same length n): | |
| open_p, high, low, close, volume :: Vector{Float64} | |
| params :: Dict{String,Float64} β one value per key from get_param_grid() | |
| Returns Vector{Int} of length n: | |
| 1 = enter/hold long | |
| -1 = enter/hold short | |
| 0 = flat / no position | |
| Rules: | |
| - Return 0 for the first ~slow_period bars (warmup / NaN period) | |
| - Always use isnan() checks before comparisons | |
| - Signals are position signals, not entry triggers | |
| (engine manages entries/exits from signal transitions) | |
| """ | |
| function generate_signals( | |
| open_p :: Vector{Float64}, | |
| high :: Vector{Float64}, | |
| low :: Vector{Float64}, | |
| close :: Vector{Float64}, | |
| volume :: Vector{Float64}, | |
| params :: Dict{String, Float64}, | |
| ) :: Vector{Int} | |
| n = length(close) | |
| fast_p = Int(round(get(params, "fast_period", 20.0))) | |
| slow_p = Int(round(get(params, "slow_period", 50.0))) | |
| atr_p = Int(round(get(params, "atr_filter", 14.0))) | |
| fast_ema = ema(close, fast_p) | |
| slow_ema = ema(close, slow_p) | |
| atr_vals = atr(high, low, close, atr_p) | |
| signals = zeros(Int, n) | |
| for i in (slow_p + 1):n | |
| # Skip if any indicator is NaN (still in warmup) | |
| isnan(fast_ema[i]) && continue | |
| isnan(slow_ema[i]) && continue | |
| isnan(atr_vals[i]) && continue | |
| # Optional: ATR volatility filter β only trade when market is moving | |
| atr_threshold = close[i] * 0.001 # 0.1% of price | |
| atr_vals[i] < atr_threshold && continue | |
| if fast_ema[i] > slow_ema[i] | |
| signals[i] = 1 # bullish: long | |
| elseif fast_ema[i] < slow_ema[i] | |
| signals[i] = -1 # bearish: short | |
| else | |
| signals[i] = 0 # neutral | |
| end | |
| end | |
| return signals | |
| end | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Example 2: RSI Mean Reversion | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # function get_param_grid() | |
| # return Dict( | |
| # "rsi_period" => [7.0, 10.0, 14.0, 21.0], | |
| # "oversold" => [25.0, 30.0, 35.0], | |
| # "overbought" => [65.0, 70.0, 75.0], | |
| # "ma_period" => [20.0, 50.0], | |
| # ) | |
| # end | |
| # | |
| # function generate_signals(open_p, high, low, close, volume, params) | |
| # n = length(close) | |
| # rsi_p = Int(round(get(params, "rsi_period", 14.0))) | |
| # oversold = get(params, "oversold", 30.0) | |
| # overbought = get(params, "overbought", 70.0) | |
| # ma_p = Int(round(get(params, "ma_period", 50.0))) | |
| # | |
| # rsi_vals = rsi(close, rsi_p) | |
| # trend_ma = sma(close, ma_p) | |
| # signals = zeros(Int, n) | |
| # | |
| # for i in (ma_p + rsi_p + 1):n | |
| # isnan(rsi_vals[i]) && continue | |
| # isnan(trend_ma[i]) && continue | |
| # | |
| # # Mean reversion: buy oversold in uptrend, sell overbought in downtrend | |
| # if rsi_vals[i] < oversold && close[i] > trend_ma[i] | |
| # signals[i] = 1 | |
| # elseif rsi_vals[i] > overbought && close[i] < trend_ma[i] | |
| # signals[i] = -1 | |
| # end | |
| # end | |
| # return signals | |
| # end | |