157 lines
4.1 KiB
JavaScript
157 lines
4.1 KiB
JavaScript
/**
|
|
* Python Service Client
|
|
* Handles communication with the Python processing service
|
|
*/
|
|
// Use native fetch (Node.js 18+) or node-fetch for older versions
|
|
let fetch;
|
|
if (typeof globalThis.fetch !== 'undefined') {
|
|
// Node.js 18+ has native fetch
|
|
fetch = globalThis.fetch;
|
|
} else {
|
|
// Fallback: dynamically import node-fetch
|
|
try {
|
|
const nodeFetch = require('node-fetch');
|
|
fetch = nodeFetch.default || nodeFetch;
|
|
} catch (e) {
|
|
// If node-fetch is not available, we'll handle it in the functions
|
|
fetch = null;
|
|
}
|
|
}
|
|
|
|
const PYTHON_SERVICE_URL = process.env.PYTHON_SERVICE_URL || 'http://localhost:8010';
|
|
|
|
/**
|
|
* Call Python service for options flow processing
|
|
* @param {Object} params - Query parameters
|
|
* @returns {Promise<Object>} Processed options flow data
|
|
*/
|
|
export async function getOptionsFlowFromPython(params = {}) {
|
|
if (!fetch) {
|
|
throw new Error('Fetch is not available. Please install node-fetch or use Node.js 18+');
|
|
}
|
|
|
|
const {
|
|
startDate,
|
|
endDate,
|
|
minPremium = 80000,
|
|
tolPct = 0.20
|
|
} = params;
|
|
|
|
const queryParams = new URLSearchParams();
|
|
if (startDate) queryParams.append('start_date', startDate);
|
|
if (endDate) queryParams.append('end_date', endDate);
|
|
if (minPremium) queryParams.append('min_premium', minPremium);
|
|
if (tolPct) queryParams.append('tol_pct', tolPct);
|
|
|
|
const url = `${PYTHON_SERVICE_URL}/api/options-flow?${queryParams.toString()}`;
|
|
|
|
try {
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), 30000);
|
|
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
signal: controller.signal
|
|
});
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
throw new Error(`Python service error: ${response.status} - ${errorText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error calling Python service:', error);
|
|
|
|
// Fallback to SQL if Python service is unavailable
|
|
if (error.name === 'AbortError' ||
|
|
error.code === 'ECONNREFUSED' ||
|
|
error.code === 'ETIMEDOUT' ||
|
|
error.message.includes('fetch')) {
|
|
console.warn('Python service unavailable, falling back to SQL');
|
|
throw new Error('PYTHON_SERVICE_UNAVAILABLE');
|
|
}
|
|
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if Python service is healthy
|
|
* @returns {Promise<boolean>}
|
|
*/
|
|
export async function checkPythonServiceHealth() {
|
|
if (!fetch) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
|
|
const response = await fetch(`${PYTHON_SERVICE_URL}/health`, {
|
|
method: 'GET',
|
|
signal: controller.signal
|
|
});
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
if (!response.ok) {
|
|
return false;
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data.status === 'healthy';
|
|
} catch (error) {
|
|
console.warn('Python service health check failed:', error.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get flow statistics from Python service
|
|
* @param {string} symbol - Optional symbol filter
|
|
* @returns {Promise<Object>}
|
|
*/
|
|
export async function getFlowStatsFromPython(symbol = null) {
|
|
if (!fetch) {
|
|
throw new Error('Fetch is not available');
|
|
}
|
|
|
|
const queryParams = new URLSearchParams();
|
|
if (symbol) queryParams.append('symbol', symbol);
|
|
|
|
const url = `${PYTHON_SERVICE_URL}/api/options-flow/stats?${queryParams.toString()}`;
|
|
|
|
try {
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
signal: controller.signal
|
|
});
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Python service error: ${response.status}`);
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error('Error getting flow stats from Python service:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|