404 lines
13 KiB
Python
404 lines
13 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
SmartBot AI Endpoint dengan ChatGPT Support
|
|
===========================================
|
|
|
|
Endpoint AI yang mendukung multiple AI providers:
|
|
- ChatGPT (OpenAI)
|
|
- Local AI Model
|
|
- Custom AI Model
|
|
|
|
Installation:
|
|
pip install flask pandas numpy openai requests python-dotenv
|
|
|
|
Usage:
|
|
python ai_endpoint_chatgpt.py
|
|
"""
|
|
|
|
from flask import Flask, request, jsonify
|
|
import json
|
|
import requests
|
|
from datetime import datetime
|
|
import logging
|
|
import os
|
|
from dotenv import load_dotenv
|
|
|
|
# Load environment variables
|
|
load_dotenv()
|
|
|
|
# Setup logging
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
app = Flask(__name__)
|
|
|
|
class ChatGPTProvider:
|
|
"""ChatGPT AI Provider"""
|
|
|
|
def __init__(self):
|
|
self.api_key = os.getenv('OPENAI_API_KEY')
|
|
self.endpoint_url = "https://api.openai.com/v1/chat/completions"
|
|
self.model = "gpt-3.5-turbo"
|
|
|
|
def analyze_trade(self, data):
|
|
"""Analyze trade using ChatGPT"""
|
|
try:
|
|
if not self.api_key:
|
|
return self._create_error_response("OpenAI API key not configured")
|
|
|
|
# Create prompt
|
|
prompt = self._create_analysis_prompt(data)
|
|
|
|
# Call ChatGPT API
|
|
response = self._call_chatgpt_api(prompt)
|
|
|
|
# Parse response
|
|
return self._parse_chatgpt_response(response, data)
|
|
|
|
except Exception as e:
|
|
logger.error(f"ChatGPT analysis error: {e}")
|
|
return self._create_error_response(f"ChatGPT error: {str(e)}")
|
|
|
|
def _create_analysis_prompt(self, data):
|
|
"""Create analysis prompt for ChatGPT"""
|
|
pair = data.get('pair', 'Unknown')
|
|
candidate = data.get('candidate', 'Unknown')
|
|
mode = data.get('mode', 'intraday')
|
|
|
|
indicators = data.get('indicators', {})
|
|
rsi = indicators.get('rsi', 0)
|
|
adx = indicators.get('adx', 0)
|
|
ema_fast = indicators.get('ema_fast', 0)
|
|
ema_slow = indicators.get('ema_slow', 0)
|
|
|
|
spread = data.get('spread', 0)
|
|
atr = data.get('atr', 0)
|
|
confirmations = data.get('confirmations', 0)
|
|
signal_strength = data.get('signal_strength', 0)
|
|
|
|
prompt = f"""
|
|
Analyze this forex trading signal for {pair}:
|
|
|
|
Signal: {candidate}
|
|
Mode: {mode}
|
|
Strength: {signal_strength}/100
|
|
Confirmations: {confirmations}/6
|
|
RSI: {rsi}
|
|
ADX: {adx}
|
|
EMA: {ema_fast}/{ema_slow}
|
|
Spread: {spread} points
|
|
ATR: {atr}
|
|
|
|
Provide analysis in JSON format:
|
|
{{
|
|
"verdict": "confirm_buy|confirm_sell|reject",
|
|
"confidence": 0.85,
|
|
"reason": "Explanation...",
|
|
"suggested_sl": 1.2345,
|
|
"suggested_tp": 1.2456
|
|
}}
|
|
"""
|
|
return prompt
|
|
|
|
def _call_chatgpt_api(self, prompt):
|
|
"""Call ChatGPT API"""
|
|
headers = {
|
|
'Authorization': f'Bearer {self.api_key}',
|
|
'Content-Type': 'application/json'
|
|
}
|
|
|
|
payload = {
|
|
'model': self.model,
|
|
'messages': [
|
|
{'role': 'system', 'content': 'You are a forex trading AI. Respond in JSON format only.'},
|
|
{'role': 'user', 'content': prompt}
|
|
],
|
|
'temperature': 0.3,
|
|
'max_tokens': 500
|
|
}
|
|
|
|
response = requests.post(self.endpoint_url, headers=headers, json=payload)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
def _parse_chatgpt_response(self, response, original_data):
|
|
"""Parse ChatGPT response"""
|
|
try:
|
|
content = response['choices'][0]['message']['content']
|
|
|
|
# Extract JSON
|
|
json_start = content.find('{')
|
|
json_end = content.rfind('}') + 1
|
|
|
|
if json_start != -1 and json_end != 0:
|
|
json_str = content[json_start:json_end]
|
|
ai_response = json.loads(json_str)
|
|
|
|
# Add metadata
|
|
ai_response['timestamp'] = datetime.now().isoformat()
|
|
ai_response['ai_provider'] = 'chatgpt'
|
|
|
|
return ai_response
|
|
else:
|
|
return self._create_error_response("Invalid JSON response")
|
|
|
|
except Exception as e:
|
|
return self._create_error_response(f"Response parsing error: {str(e)}")
|
|
|
|
def _create_error_response(self, error_msg):
|
|
return {
|
|
'verdict': 'reject',
|
|
'confidence': 0.0,
|
|
'reason': error_msg,
|
|
'timestamp': datetime.now().isoformat(),
|
|
'ai_provider': 'chatgpt'
|
|
}
|
|
|
|
class LocalAIProvider:
|
|
"""Local AI Provider (Original SmartBot AI)"""
|
|
|
|
def __init__(self):
|
|
self.confidence_threshold = 0.7
|
|
self.min_signal_strength = 60
|
|
|
|
def analyze_trade(self, data):
|
|
"""Analyze trade using local AI logic"""
|
|
try:
|
|
candidate = data.get('candidate', '')
|
|
if not candidate:
|
|
return self._create_response('reject', 0.0, 'No trading candidate specified')
|
|
|
|
# Calculate confidence
|
|
confidence = self._calculate_confidence(data, candidate)
|
|
|
|
# Decision logic
|
|
if confidence < self.confidence_threshold:
|
|
return self._create_response('reject', confidence,
|
|
f'Confidence too low ({confidence:.2f} < {self.confidence_threshold})')
|
|
|
|
# Check signal strength
|
|
signal_strength = data.get('signal_strength', 0)
|
|
if signal_strength < self.min_signal_strength:
|
|
return self._create_response('reject', confidence,
|
|
f'Signal strength too low ({signal_strength} < {self.min_signal_strength})')
|
|
|
|
# Check confirmations
|
|
confirmations = data.get('confirmations', 0)
|
|
if confirmations < 3:
|
|
return self._create_response('reject', confidence,
|
|
f'Insufficient confirmations ({confirmations} < 3)')
|
|
|
|
# Generate TP/SL suggestions
|
|
tp_sl = self._calculate_optimal_tp_sl(data, candidate)
|
|
|
|
# Decision
|
|
if candidate == 'BUY':
|
|
verdict = 'confirm_buy'
|
|
reason = f'Strong buy signal with {confidence:.2f} confidence'
|
|
elif candidate == 'SELL':
|
|
verdict = 'confirm_sell'
|
|
reason = f'Strong sell signal with {confidence:.2f} confidence'
|
|
else:
|
|
return self._create_response('reject', confidence, 'Invalid candidate')
|
|
|
|
return self._create_response(verdict, confidence, reason, tp_sl)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Local AI analysis error: {e}")
|
|
return self._create_response('reject', 0.0, f'Error in analysis: {str(e)}')
|
|
|
|
def _calculate_confidence(self, data, candidate):
|
|
"""Calculate confidence level"""
|
|
try:
|
|
signal_strength = data.get('signal_strength', 0)
|
|
confirmations = data.get('confirmations', 0)
|
|
|
|
# Base confidence
|
|
base_confidence = min(signal_strength / 100.0, 1.0)
|
|
confirmation_bonus = min(confirmations * 0.1, 0.3)
|
|
|
|
# Market condition adjustments
|
|
indicators = data.get('indicators', {})
|
|
rsi = indicators.get('rsi', 50)
|
|
adx = indicators.get('adx', 25)
|
|
|
|
# RSI adjustment
|
|
if candidate == 'BUY' and rsi > 70:
|
|
base_confidence -= 0.1
|
|
elif candidate == 'SELL' and rsi < 30:
|
|
base_confidence -= 0.1
|
|
|
|
# ADX adjustment
|
|
if adx < 20:
|
|
base_confidence -= 0.05
|
|
|
|
# Spread penalty
|
|
spread = data.get('spread', 0)
|
|
if spread > 500:
|
|
base_confidence -= 0.1
|
|
elif spread > 300:
|
|
base_confidence -= 0.05
|
|
|
|
final_confidence = max(0.0, min(1.0, base_confidence + confirmation_bonus))
|
|
return final_confidence
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error calculating confidence: {e}")
|
|
return 0.5
|
|
|
|
def _calculate_optimal_tp_sl(self, data, candidate):
|
|
"""Calculate optimal TP/SL levels"""
|
|
try:
|
|
indicators = data.get('indicators', {})
|
|
ema_fast = indicators.get('ema_fast', 0)
|
|
ema_slow = indicators.get('ema_slow', 0)
|
|
atr = data.get('atr', 0.001)
|
|
|
|
current_price = (ema_fast + ema_slow) / 2
|
|
|
|
if candidate == 'BUY':
|
|
suggested_sl = current_price - (atr * 1.5)
|
|
suggested_tp = current_price + (atr * 2.0)
|
|
else: # SELL
|
|
suggested_sl = current_price + (atr * 1.5)
|
|
suggested_tp = current_price - (atr * 2.0)
|
|
|
|
return {
|
|
'suggested_sl': round(suggested_sl, 5),
|
|
'suggested_tp': round(suggested_tp, 5)
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error calculating TP/SL: {e}")
|
|
return None
|
|
|
|
def _create_response(self, verdict, confidence, reason, tp_sl=None):
|
|
"""Create standardized response"""
|
|
response = {
|
|
'verdict': verdict,
|
|
'confidence': round(confidence, 3),
|
|
'reason': reason,
|
|
'timestamp': datetime.now().isoformat(),
|
|
'ai_provider': 'local'
|
|
}
|
|
|
|
if tp_sl:
|
|
response.update(tp_sl)
|
|
|
|
return response
|
|
|
|
class AIFactory:
|
|
"""Factory for creating AI providers"""
|
|
|
|
@staticmethod
|
|
def create_provider(provider_type):
|
|
"""Create AI provider based on type"""
|
|
if provider_type == "chatgpt":
|
|
return ChatGPTProvider()
|
|
else:
|
|
return LocalAIProvider() # Default to local AI
|
|
|
|
# Initialize AI factory
|
|
ai_factory = AIFactory()
|
|
|
|
@app.route('/ai/trade', methods=['POST'])
|
|
def trade_analysis():
|
|
"""Main endpoint for trading analysis"""
|
|
try:
|
|
# Get request data
|
|
data = request.get_json()
|
|
|
|
if not data:
|
|
return jsonify({
|
|
'error': 'No data provided',
|
|
'verdict': 'reject'
|
|
}), 400
|
|
|
|
# Get AI provider type from request
|
|
ai_provider_type = data.get('ai_provider', 'local').lower()
|
|
|
|
logger.info(f"Received trade analysis request: {data.get('pair', 'Unknown')} using {ai_provider_type}")
|
|
|
|
# Create AI provider
|
|
ai_provider = ai_factory.create_provider(ai_provider_type)
|
|
|
|
# Generate AI decision
|
|
decision = ai_provider.analyze_trade(data)
|
|
|
|
logger.info(f"AI Decision ({ai_provider_type}): {decision['verdict']} (confidence: {decision['confidence']})")
|
|
|
|
return jsonify(decision)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error in trade analysis: {e}")
|
|
return jsonify({
|
|
'error': str(e),
|
|
'verdict': 'reject',
|
|
'confidence': 0.0,
|
|
'reason': f'Server error: {str(e)}',
|
|
'ai_provider': 'unknown'
|
|
}), 500
|
|
|
|
@app.route('/ai/providers', methods=['GET'])
|
|
def list_providers():
|
|
"""List available AI providers"""
|
|
return jsonify({
|
|
'providers': [
|
|
{
|
|
'name': 'local',
|
|
'description': 'Local SmartBot AI (Default)',
|
|
'features': ['Fast response', 'No API key needed', 'Basic analysis']
|
|
},
|
|
{
|
|
'name': 'chatgpt',
|
|
'description': 'ChatGPT AI (OpenAI)',
|
|
'features': ['Advanced analysis', 'Natural language reasoning', 'Requires API key']
|
|
}
|
|
],
|
|
'usage': {
|
|
'method': 'POST',
|
|
'url': '/ai/trade',
|
|
'body_format': {
|
|
'ai_provider': 'string (local|chatgpt)',
|
|
'pair': 'string',
|
|
'candidate': 'string (BUY|SELL)',
|
|
'mode': 'string (scalping|intraday|swing)',
|
|
'indicators': 'object',
|
|
'spread': 'integer',
|
|
'atr': 'float',
|
|
'confirmations': 'integer',
|
|
'signal_strength': 'float'
|
|
}
|
|
}
|
|
})
|
|
|
|
@app.route('/health', methods=['GET'])
|
|
def health_check():
|
|
"""Health check endpoint"""
|
|
return jsonify({
|
|
'status': 'healthy',
|
|
'service': 'SmartBot AI with ChatGPT Support',
|
|
'version': '2.0.0',
|
|
'timestamp': datetime.now().isoformat(),
|
|
'providers': ['local', 'chatgpt']
|
|
})
|
|
|
|
if __name__ == '__main__':
|
|
print("🤖 SmartBot AI Endpoint with ChatGPT Support Starting...")
|
|
print("📍 Endpoint: http://localhost:5000/ai/trade")
|
|
print("🔧 AI Providers: local, chatgpt")
|
|
print("📊 Health Check: http://localhost:5000/health")
|
|
print("=" * 50)
|
|
|
|
# Check environment variables
|
|
if os.getenv('OPENAI_API_KEY'):
|
|
print("✅ OpenAI API key found - ChatGPT available")
|
|
else:
|
|
print("⚠️ OpenAI API key not found - ChatGPT disabled")
|
|
|
|
print("=" * 50)
|
|
|
|
# Run the Flask app
|
|
app.run(host='0.0.0.0', port=5000, debug=True)
|