Article-22220-Real-Time-Ent.../Server.py

156 lines
4.7 KiB
Python
Raw Permalink Normal View History

2026-06-02 15:05:50 +02:00
# Copyright 2025, MetaQuotes Ltd.
# https://www.mql5.com/en/users/johnhlomohang/
from flask import Flask, request, jsonify
import numpy as np
import torch
import joblib
from collections import deque
import time
import json
from Model import EntropyModel
from Features import build_features, VolatilityRegimeDetector
import logging
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR) # Only show errors, not every request
app = Flask(__name__)
# Load model and scaler
try:
model = EntropyModel()
model.load_state_dict(torch.load("entropy_model.pth", map_location='cpu'))
model.eval()
print("Model loaded")
except:
model = None
print("Model not loaded")
try:
scaler = joblib.load("scaler.pkl")
print("Scaler loaded")
except:
scaler = None
print("Scaler not loaded")
# Fast regime detector with shorter history for tick-level responsiveness
regime_detector = VolatilityRegimeDetector(window_size=50, history_size=50)
# Track entropy for delta calculation
entropy_history = deque(maxlen=10)
last_entropy = None
@app.route('/predict', methods=['POST'])
def predict():
global last_entropy
try:
data = request.json
prices = np.array(data["prices"], dtype=np.float32)
rsi = float(data.get("rsi", 50.0))
# Fast feature calculation
features, metrics = build_features(prices, rsi, None, None)
# Track entropy for delta
current_entropy = metrics['entropy']
delta_entropy = 0.0 if last_entropy is None else current_entropy - last_entropy
last_entropy = current_entropy
entropy_history.append(current_entropy)
# Detect regime
regime_info = regime_detector.update(metrics)
# Scale and predict
if scaler is not None and model is not None:
scaled = scaler.transform([features])
x = torch.tensor(scaled, dtype=torch.float32)
with torch.no_grad():
prob = model(x).item()
else:
prob = 0.5
# Adaptive signal with entropy momentum
signal = generate_adaptive_signal(prob, metrics, regime_info, delta_entropy)
confidence = calculate_confidence(prob, metrics, regime_info, delta_entropy)
return jsonify({
"probability": float(prob),
"entropy": float(metrics['entropy']),
"vol_entropy": float(metrics['vol_entropy']),
"delta_entropy": float(delta_entropy),
"signal": signal,
"regime": regime_info['regime'],
"volatility_multiplier": float(regime_info['volatility_multiplier']),
"confidence": float(confidence),
"entropy_momentum": float(calculate_entropy_momentum())
})
except Exception as e:
return jsonify({"signal": "HOLD", "error": str(e)}), 200
def generate_adaptive_signal(prob, metrics, regime_info, delta_entropy):
"""Fast adaptive signal generation for tick-level trading."""
entropy = metrics['entropy']
regime = regime_info['regime']
# Base thresholds
buy_threshold = 0.60
sell_threshold = 0.40
# Adjust for regime
if regime == "HIGH_VOLATILITY":
buy_threshold = 0.65
sell_threshold = 0.35
elif regime == "LOW_VOLATILITY":
buy_threshold = 0.55
sell_threshold = 0.45
# Entropy momentum adjustment
if delta_entropy > 0.02: # Increasing entropy = increasing uncertainty
buy_threshold += 0.05
sell_threshold -= 0.05
if prob > buy_threshold:
return "BUY"
elif prob < sell_threshold:
return "SELL"
else:
return "HOLD"
def calculate_confidence(prob, metrics, regime_info, delta_entropy):
"""Confidence score with entropy penalty."""
base_conf = abs(prob - 0.5) * 2
# Penalize high entropy
entropy_penalty = metrics['entropy'] * 0.3
# Penalize increasing entropy
if delta_entropy > 0:
entropy_penalty += delta_entropy * 2
confidence = base_conf - entropy_penalty
return max(0.0, min(1.0, confidence))
def calculate_entropy_momentum():
"""Calculate entropy momentum from history."""
if len(entropy_history) < 3:
return 0.0
hist = list(entropy_history)
return hist[-1] - hist[0]
@app.route('/health', methods=['GET'])
def health():
return jsonify({"status": "ready"})
if __name__ == "__main__":
print("\n" + "="*50)
print("TICK-LEVEL ENTROPY SERVER")
print("="*50)
app.run(host="127.0.0.1", port=5000, debug=False, threaded=True)