Files
openclaw-backups/skills/openclaw-self-healing/scripts/tqqq-monitor-with-retry.js

141 lines
3.7 KiB
JavaScript

#!/usr/bin/env node
/**
* TQQQ Monitor with Auto-Retry (Level 1 Self-Improvement)
*
* Wraps the Python yahoo-finance script with automatic retry
* Closes the loop: API failure → Retry → Success
*/
const { executeWithNotifications } = require('../lib/auto-retry');
const { exec } = require('child_process');
const path = require('path');
const fs = require('fs');
// ============================================================================
// Configuration
// ============================================================================
const CONFIG = {
PYTHON_SCRIPT: path.join(process.env.HOME, 'openclaw/skills/yahoo-finance/yf'),
SYMBOL: 'TQQQ',
// Retry settings
MAX_RETRIES: 3,
BACKOFF: 'exponential',
// Discord
DISCORD_WEBHOOK: JSON.parse(
fs.readFileSync(path.join(process.env.HOME, '.openclaw/monitoring.json'), 'utf8')
).webhook.url,
// TQQQ position (from MEMORY.md)
POSITION: {
avgPrice: 50.79,
shares: 137,
totalInvested: 10096898 // ₩10,096,898
},
// Strategy lines
STRATEGY: {
stopLoss: 47.00, // -7.5%
buyMore: 49.26, // -3%
takeProfit: 52.31 // +3%
}
};
// ============================================================================
// Execute Python Script
// ============================================================================
async function fetchTQQQ() {
return new Promise((resolve, reject) => {
const startTime = Date.now();
exec(`${CONFIG.PYTHON_SCRIPT} ${CONFIG.SYMBOL}`, {
timeout: 15000, // 15초 타임아웃
maxBuffer: 10 * 1024 * 1024 // 10MB
}, (error, stdout, stderr) => {
const duration = Date.now() - startTime;
if (error) {
// Error classification for retry decision
if (error.killed || error.signal === 'SIGTERM') {
error.code = 'ETIMEDOUT';
}
error.duration = duration;
reject(error);
} else {
resolve({
output: stdout,
stderr: stderr,
duration: duration
});
}
});
});
}
// ============================================================================
// Main
// ============================================================================
async function main() {
console.log('📊 TQQQ 15분 모니터링 (with Auto-Retry)\n');
try {
// Execute with auto-retry
const result = await executeWithNotifications(
fetchTQQQ,
{
maxRetries: CONFIG.MAX_RETRIES,
backoff: CONFIG.BACKOFF,
discordWebhook: CONFIG.DISCORD_WEBHOOK,
taskName: 'TQQQ 15분 모니터링',
context: {
cron: 'TQQQ 15분 모니터링',
schedule: '*/15 * * * *',
symbol: CONFIG.SYMBOL
}
}
);
// Success!
console.log('\n✅ Success');
console.log(` Attempts: ${result.attempts}`);
console.log(` Duration: ${result.totalDuration}ms`);
console.log(` Script execution: ${result.result.duration}ms`);
// Output the Python script result
console.log('\n' + result.result.output);
if (result.result.stderr) {
console.error('\nStderr:', result.result.stderr);
}
// Exit with success
process.exit(0);
} catch (error) {
// Final failure after all retries
console.error('\n❌ Failed after all retries');
console.error(` Error: ${error.message}`);
if (error.stderr) {
console.error(` Stderr: ${error.stderr}`);
}
// Exit with error
process.exit(1);
}
}
// ============================================================================
// Run
// ============================================================================
if (require.main === module) {
main();
}
module.exports = { fetchTQQQ, CONFIG };