Initial commit: Mad Turtle v2.0 ML EA for XAUUSD H1 with Python inference server and MQL5 EA
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
Build a minimal ONNX ensemble model using raw ONNX ops (no sklearn needed).
|
||||
Creates a simple linear classifier + softmax as a demo.
|
||||
Replace this with a real trained model later (Python 3.11/3.12 + sklearn + skl2onnx).
|
||||
"""
|
||||
|
||||
import json
|
||||
import numpy as np
|
||||
import onnx
|
||||
from onnx import helper, TensorProto, numpy_helper
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
MODELS_DIR = ROOT / "models"
|
||||
MODELS_DIR.mkdir(exist_ok=True)
|
||||
|
||||
FEATURES = [
|
||||
"returns_1", "returns_3", "returns_6",
|
||||
"sma_10", "sma_20", "sma_50",
|
||||
"macd", "macd_signal",
|
||||
"rsi_14", "atr_14", "atr_pct",
|
||||
"vol_ratio", "high_low_range", "dist_sma20",
|
||||
]
|
||||
|
||||
# Dummy weights for demo — replace with real trained weights
|
||||
rng = np.random.default_rng(123)
|
||||
W = rng.standard_normal((14, 3)).astype(np.float32) * 0.1
|
||||
b = np.zeros(3, dtype=np.float32)
|
||||
|
||||
# Normalize weights roughly
|
||||
W = W / np.maximum(np.abs(W).sum(axis=0, keepdims=True), 1e-6)
|
||||
|
||||
scale = np.array([
|
||||
1000.0, 1000.0, 1000.0,
|
||||
1.0, 1.0, 1.0,
|
||||
10.0, 10.0,
|
||||
1.0, 10.0, 1.0,
|
||||
1.0, 1.0, 1.0,
|
||||
], dtype=np.float32).reshape(1, 14)
|
||||
|
||||
bias = np.zeros((1, 14), dtype=np.float32)
|
||||
|
||||
|
||||
def build_model():
|
||||
# Input
|
||||
x = helper.make_tensor_value_info("float_input", TensorProto.FLOAT, [None, 14])
|
||||
|
||||
# Scale nodes: x_scaled = x * scale + bias
|
||||
scale_tensor = numpy_helper.from_array(scale, name="scale")
|
||||
bias_tensor = numpy_helper.from_array(bias, name="bias")
|
||||
mul_node = helper.make_node("Mul", ["float_input", "scale"], ["x_scaled"])
|
||||
add_node = helper.make_node("Add", ["x_scaled", "bias"], ["x_scaled_centered"])
|
||||
|
||||
# Linear layer: logits = x_scaled @ W + b
|
||||
W_tensor = numpy_helper.from_array(W, name="W")
|
||||
b_tensor = numpy_helper.from_array(b, name="b")
|
||||
matmul_node = helper.make_node("MatMul", ["x_scaled_centered", "W"], ["logits"])
|
||||
add_bias_node = helper.make_node("Add", ["logits", "b"], ["logits_biased"])
|
||||
|
||||
# Softmax
|
||||
softmax_node = helper.make_node("Softmax", ["logits_biased"], ["probs"], axis=1)
|
||||
|
||||
# Output
|
||||
y = helper.make_tensor_value_info("probs", TensorProto.FLOAT, [None, 3])
|
||||
|
||||
graph = helper.make_graph(
|
||||
[mul_node, add_node, matmul_node, add_bias_node, softmax_node],
|
||||
"mad_turtle_ensemble",
|
||||
[x],
|
||||
[y],
|
||||
[scale_tensor, bias_tensor, W_tensor, b_tensor],
|
||||
)
|
||||
model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 15)])
|
||||
model.ir_version = 8
|
||||
onnx.checker.check_model(model)
|
||||
out = MODELS_DIR / "xauusd_h1_ensemble.onnx"
|
||||
onnx.save(model, str(out))
|
||||
print(f"Saved demo ONNX model -> {out}")
|
||||
|
||||
|
||||
def save_metadata():
|
||||
meta = {
|
||||
"symbol": "XAUUSD",
|
||||
"timeframe": "H1",
|
||||
"features": FEATURES,
|
||||
"target_horizon": 3,
|
||||
"built_at": __import__('datetime').datetime.utcnow().isoformat(),
|
||||
"models": {
|
||||
"ensemble": {
|
||||
"features": FEATURES,
|
||||
"path": "models/xauusd_h1_ensemble.onnx",
|
||||
"note": "Demo model with random weights. Replace with real trained model.",
|
||||
}
|
||||
},
|
||||
}
|
||||
out = MODELS_DIR / "metadata.json"
|
||||
with open(out, "w") as f:
|
||||
json.dump(meta, f, indent=2)
|
||||
print(f"Saved metadata -> {out}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
build_model()
|
||||
save_metadata()
|
||||
Reference in New Issue
Block a user