feat: fix Safe Paper Trading display formatting and API sync
- Fixed field mapping between API and frontend (amount→positionSize, entry→entryPrice, createdAt→timestamp) - Updated API sync function to properly convert API trade format to frontend format - Resolved display issues: 'Invalid Date', missing entry price, missing trade size - Added trade monitoring system and automation improvements - Enhanced automation with simple-automation.js for reliable 24/7 operation - Working automation now detecting 85% confidence BUY signals and executing trades
This commit is contained in:
@@ -4,6 +4,11 @@ import { NextResponse } from 'next/server'
|
|||||||
let paperTrades = []
|
let paperTrades = []
|
||||||
let tradeIdCounter = 1
|
let tradeIdCounter = 1
|
||||||
|
|
||||||
|
// Export function to get trades (for other API routes)
|
||||||
|
export function getAllPaperTrades() {
|
||||||
|
return paperTrades
|
||||||
|
}
|
||||||
|
|
||||||
export async function POST(request) {
|
export async function POST(request) {
|
||||||
try {
|
try {
|
||||||
const tradeData = await request.json()
|
const tradeData = await request.json()
|
||||||
|
|||||||
34
app/api/safe-paper-trading/trades/route.js
Normal file
34
app/api/safe-paper-trading/trades/route.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { getAllPaperTrades } from '../create-trade/route.js'
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
const trades = getAllPaperTrades()
|
||||||
|
|
||||||
|
// Calculate stats
|
||||||
|
const totalTrades = trades.length
|
||||||
|
const totalValue = trades.reduce((sum, trade) => {
|
||||||
|
return sum + (trade.side === 'BUY' ? -trade.amount : trade.amount) + trade.pnl
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const buyTrades = trades.filter(t => t.side === 'BUY').length
|
||||||
|
const sellTrades = trades.filter(t => t.side === 'SELL').length
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
trades: trades,
|
||||||
|
totalTrades,
|
||||||
|
totalValue,
|
||||||
|
buyTrades,
|
||||||
|
sellTrades,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching paper trades:', error)
|
||||||
|
return NextResponse.json({
|
||||||
|
success: false,
|
||||||
|
message: 'Failed to fetch paper trades',
|
||||||
|
error: error.message
|
||||||
|
}, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -440,6 +440,68 @@ export default function SafePaperTradingPage() {
|
|||||||
console.log('📂 Restored paper balance from localStorage')
|
console.log('📂 Restored paper balance from localStorage')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync with API trades (from automation)
|
||||||
|
const syncApiTrades = async () => {
|
||||||
|
try {
|
||||||
|
console.log('🔄 Syncing trades from API...')
|
||||||
|
const response = await fetch('/api/safe-paper-trading/trades')
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json()
|
||||||
|
if (data.success && data.trades.length > 0) {
|
||||||
|
console.log(`📈 Found ${data.trades.length} API trades, syncing with localStorage...`)
|
||||||
|
|
||||||
|
// Get existing localStorage trades
|
||||||
|
const existingTrades = JSON.parse(localStorage.getItem('safePaperTrading_paperTrades') || '[]')
|
||||||
|
|
||||||
|
// Convert API trades to frontend format and filter out existing ones
|
||||||
|
const existingIds = new Set(existingTrades.map(t => t.id))
|
||||||
|
const newTrades = data.trades
|
||||||
|
.filter(t => !existingIds.has(t.id))
|
||||||
|
.map(apiTrade => ({
|
||||||
|
id: apiTrade.id,
|
||||||
|
symbol: apiTrade.symbol,
|
||||||
|
side: apiTrade.side,
|
||||||
|
positionSize: apiTrade.amount, // Map amount to positionSize
|
||||||
|
entryPrice: apiTrade.entry, // Map entry to entryPrice
|
||||||
|
confidence: apiTrade.confidence,
|
||||||
|
reasoning: apiTrade.reasoning,
|
||||||
|
source: apiTrade.source,
|
||||||
|
status: apiTrade.status,
|
||||||
|
timestamp: apiTrade.createdAt, // Map createdAt to timestamp
|
||||||
|
pnl: apiTrade.pnl || 0,
|
||||||
|
fees: apiTrade.fees || 0
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (newTrades.length > 0) {
|
||||||
|
const combinedTrades = [...existingTrades, ...newTrades]
|
||||||
|
setPaperTrades(combinedTrades)
|
||||||
|
localStorage.setItem('safePaperTrading_paperTrades', JSON.stringify(combinedTrades))
|
||||||
|
|
||||||
|
// Update balance based on new trades
|
||||||
|
const additionalValue = newTrades.reduce((sum, trade) => {
|
||||||
|
return sum + (trade.side === 'BUY' ? -trade.positionSize : trade.positionSize)
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const newBalance = paperBalance + additionalValue
|
||||||
|
setPaperBalance(newBalance)
|
||||||
|
localStorage.setItem('safePaperTrading_paperBalance', newBalance.toString())
|
||||||
|
|
||||||
|
console.log(`✅ Synced ${newTrades.length} new trades from API`)
|
||||||
|
} else {
|
||||||
|
console.log('📊 All API trades already in localStorage')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('📊 No API trades found')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ Failed to sync API trades:', error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync API trades after loading localStorage
|
||||||
|
syncApiTrades()
|
||||||
|
|
||||||
// Fetch AI learning status
|
// Fetch AI learning status
|
||||||
fetchLearningStatus()
|
fetchLearningStatus()
|
||||||
|
|
||||||
|
|||||||
5
automation.log
Normal file
5
automation.log
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
nohup: ignoring input
|
||||||
|
[Thu Aug 7 16:00:18 CEST 2025] Running automation cycle...
|
||||||
|
🚀 Executing BUY trade at 85% confidence (entry: 171.8)
|
||||||
|
✅ Trade executed successfully: PAPER_1754575319443_2
|
||||||
|
💤 Sleeping for 1 hour...
|
||||||
@@ -5,10 +5,6 @@
|
|||||||
* Integrates Fear & Greed Index and macro indicators for better trading decisions
|
* Integrates Fear & Greed Index and macro indicators for better trading decisions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { exec } = require('child_process');
|
|
||||||
const { promisify } = require('util');
|
|
||||||
const execAsync = promisify(exec);
|
|
||||||
|
|
||||||
// Import M2 Money Supply indicator
|
// Import M2 Money Supply indicator
|
||||||
const M2MoneySupplyIndicator = require('./m2-money-supply-indicator');
|
const M2MoneySupplyIndicator = require('./m2-money-supply-indicator');
|
||||||
|
|
||||||
@@ -19,6 +15,8 @@ class EnhancedGlobalAutomation {
|
|||||||
timeframe: '60',
|
timeframe: '60',
|
||||||
intervalMinutes: 60,
|
intervalMinutes: 60,
|
||||||
autoExecuteThreshold: 60,
|
autoExecuteThreshold: 60,
|
||||||
|
// API endpoint for container environment
|
||||||
|
apiHost: '192.168.0.1:9001',
|
||||||
// Enhanced with sentiment-based adjustments
|
// Enhanced with sentiment-based adjustments
|
||||||
sentimentThresholds: {
|
sentimentThresholds: {
|
||||||
extremeFear: 75, // Lower threshold during extreme fear (more aggressive)
|
extremeFear: 75, // Lower threshold during extreme fear (more aggressive)
|
||||||
@@ -125,8 +123,8 @@ class EnhancedGlobalAutomation {
|
|||||||
async estimateFearGreedFromPriceAction() {
|
async estimateFearGreedFromPriceAction() {
|
||||||
try {
|
try {
|
||||||
// Get recent analysis to estimate sentiment
|
// Get recent analysis to estimate sentiment
|
||||||
const { stdout } = await execAsync(`curl -s "http://localhost:9001/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}"`);
|
const response = await fetch(`http://${this.config.apiHost}/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`);
|
||||||
const data = JSON.parse(stdout);
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success && data.data && data.data.analysis) {
|
if (data.success && data.data && data.data.analysis) {
|
||||||
const analysis = data.data.analysis;
|
const analysis = data.data.analysis;
|
||||||
@@ -258,8 +256,8 @@ class EnhancedGlobalAutomation {
|
|||||||
await this.updateMarketSentiment();
|
await this.updateMarketSentiment();
|
||||||
|
|
||||||
// Get current technical analysis
|
// Get current technical analysis
|
||||||
const { stdout } = await execAsync(`curl -s "http://localhost:9001/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}"`);
|
const response = await fetch(`http://${this.config.apiHost}/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`);
|
||||||
const data = JSON.parse(stdout);
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success && data.data && data.data.analysis) {
|
if (data.success && data.data && data.data.analysis) {
|
||||||
const analysis = data.data.analysis;
|
const analysis = data.data.analysis;
|
||||||
@@ -322,10 +320,15 @@ class EnhancedGlobalAutomation {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create enhanced paper trade
|
// Create enhanced paper trade
|
||||||
const curlData = JSON.stringify(tradeData).replace(/"/g, '\\"');
|
const response = await fetch(`http://${this.config.apiHost}/api/safe-paper-trading/create-trade`, {
|
||||||
const { stdout: tradeResult } = await execAsync(`curl -s -X POST http://localhost:9001/api/safe-paper-trading/create-trade -H "Content-Type: application/json" -d "${curlData}"`);
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(tradeData)
|
||||||
|
});
|
||||||
|
|
||||||
const result = JSON.parse(tradeResult);
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.stats.totalTrades++;
|
this.stats.totalTrades++;
|
||||||
|
|||||||
233
host-automation.js
Normal file
233
host-automation.js
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Host-based 24/7 Trading Automation
|
||||||
|
* Runs on the host system, not inside the container
|
||||||
|
*/
|
||||||
|
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
class HostAutomation {
|
||||||
|
constructor() {
|
||||||
|
this.config = {
|
||||||
|
symbol: 'SOLUSD',
|
||||||
|
timeframe: '60',
|
||||||
|
intervalMinutes: 60,
|
||||||
|
autoExecuteThreshold: 60,
|
||||||
|
apiHost: 'localhost:9001',
|
||||||
|
requestTimeout: 30000
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stats = {
|
||||||
|
startTime: new Date(),
|
||||||
|
totalCycles: 0,
|
||||||
|
totalTrades: 0,
|
||||||
|
successfulCycles: 0,
|
||||||
|
failedCycles: 0,
|
||||||
|
lastSignal: null,
|
||||||
|
lastTrade: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async log(message) {
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
console.log(`[${timestamp}] ${message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async makeRequest(url, options = {}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const isHttps = url.startsWith('https');
|
||||||
|
const client = isHttps ? https : http;
|
||||||
|
|
||||||
|
const requestOptions = {
|
||||||
|
timeout: this.config.requestTimeout,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = client.request(url, requestOptions, (res) => {
|
||||||
|
let data = '';
|
||||||
|
res.on('data', chunk => data += chunk);
|
||||||
|
res.on('end', () => {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(data);
|
||||||
|
resolve(parsed);
|
||||||
|
} catch (e) {
|
||||||
|
resolve({ success: false, error: 'Invalid JSON response' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (error) => {
|
||||||
|
this.log(`❌ Request error: ${error.message}`);
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('timeout', () => {
|
||||||
|
this.log(`⏱️ Request timeout: ${url}`);
|
||||||
|
req.destroy();
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.body) {
|
||||||
|
req.write(options.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async makePostRequest(url, data) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const postData = JSON.stringify(data);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Content-Length': Buffer.byteLength(postData)
|
||||||
|
},
|
||||||
|
timeout: this.config.requestTimeout
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = http.request(url, options, (res) => {
|
||||||
|
let responseData = '';
|
||||||
|
res.on('data', chunk => responseData += chunk);
|
||||||
|
res.on('end', () => {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(responseData);
|
||||||
|
resolve(parsed);
|
||||||
|
} catch (e) {
|
||||||
|
resolve({ success: false, error: 'Invalid JSON response' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (error) => {
|
||||||
|
this.log(`❌ POST request error: ${error.message}`);
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('timeout', () => {
|
||||||
|
this.log(`⏱️ POST request timeout: ${url}`);
|
||||||
|
req.destroy();
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.write(postData);
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async runAnalysisCycle() {
|
||||||
|
this.stats.totalCycles++;
|
||||||
|
await this.log(`🔄 Analysis cycle #${this.stats.totalCycles}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.log(`📡 Fetching analysis from API...`);
|
||||||
|
const data = await this.makeRequest(`http://${this.config.apiHost}/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`);
|
||||||
|
|
||||||
|
if (data && data.success && data.data && data.data.analysis) {
|
||||||
|
const analysis = data.data.analysis;
|
||||||
|
this.stats.lastSignal = {
|
||||||
|
time: new Date(),
|
||||||
|
recommendation: analysis.recommendation,
|
||||||
|
confidence: analysis.confidence
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.log(`📊 Signal: ${analysis.recommendation} (${analysis.confidence}% confidence)`);
|
||||||
|
|
||||||
|
if (analysis.confidence >= this.config.autoExecuteThreshold &&
|
||||||
|
(analysis.recommendation === 'BUY' || analysis.recommendation === 'SELL')) {
|
||||||
|
|
||||||
|
await this.log(`🚀 Executing ${analysis.recommendation} trade with ${analysis.confidence}% confidence`);
|
||||||
|
|
||||||
|
const trade = await this.executeTrade(analysis);
|
||||||
|
if (trade && trade.success) {
|
||||||
|
this.stats.totalTrades++;
|
||||||
|
this.stats.lastTrade = {
|
||||||
|
time: new Date(),
|
||||||
|
type: analysis.recommendation,
|
||||||
|
confidence: analysis.confidence,
|
||||||
|
price: trade.trade?.entry || analysis.entry?.price || 'unknown'
|
||||||
|
};
|
||||||
|
await this.log(`✅ Trade executed: ${analysis.recommendation} at ${trade.trade?.entry || analysis.entry?.price}`);
|
||||||
|
} else {
|
||||||
|
await this.log(`❌ Trade execution failed`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await this.log(`⏸️ Confidence ${analysis.confidence}% below threshold ${this.config.autoExecuteThreshold}% - holding`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stats.successfulCycles++;
|
||||||
|
} else {
|
||||||
|
await this.log(`❌ No valid analysis data received`);
|
||||||
|
this.stats.failedCycles++;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
await this.log(`❌ Cycle error: ${error.message}`);
|
||||||
|
this.stats.failedCycles++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.printStats();
|
||||||
|
|
||||||
|
const nextCycle = new Date(Date.now() + this.config.intervalMinutes * 60 * 1000);
|
||||||
|
await this.log(`⏰ Next cycle: ${nextCycle.toLocaleTimeString()}`);
|
||||||
|
|
||||||
|
setTimeout(() => this.runAnalysisCycle(), this.config.intervalMinutes * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeTrade(analysis) {
|
||||||
|
try {
|
||||||
|
await this.log(`💱 Preparing trade data...`);
|
||||||
|
const tradeData = {
|
||||||
|
symbol: this.config.symbol,
|
||||||
|
side: analysis.recommendation,
|
||||||
|
amount: 100,
|
||||||
|
entry: analysis.entry?.price || 150,
|
||||||
|
confidence: analysis.confidence,
|
||||||
|
reasoning: analysis.reasoning || 'Automated trade',
|
||||||
|
source: 'host_automation_24x7'
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.log(`📤 Sending trade request...`);
|
||||||
|
const result = await this.makePostRequest(`http://${this.config.apiHost}/api/safe-paper-trading/create-trade`, tradeData);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
await this.log(`❌ Trade execution error: ${error.message}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async printStats() {
|
||||||
|
const uptime = Math.floor((Date.now() - this.stats.startTime) / 1000 / 60);
|
||||||
|
const successRate = this.stats.totalCycles > 0 ? Math.round((this.stats.successfulCycles / this.stats.totalCycles) * 100) : 0;
|
||||||
|
|
||||||
|
await this.log(`📈 Stats: ${this.stats.totalCycles} cycles (${successRate}% success), ${this.stats.totalTrades} trades, ${uptime}m uptime`);
|
||||||
|
|
||||||
|
if (this.stats.lastSignal) {
|
||||||
|
const signalAge = Math.floor((Date.now() - this.stats.lastSignal.time) / 1000 / 60);
|
||||||
|
await this.log(`🎯 Last signal: ${this.stats.lastSignal.recommendation} (${this.stats.lastSignal.confidence}%) ${signalAge}m ago`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stats.lastTrade) {
|
||||||
|
const tradeAge = Math.floor((Date.now() - this.stats.lastTrade.time) / 1000 / 60);
|
||||||
|
await this.log(`💰 Last trade: ${this.stats.lastTrade.type} at ${this.stats.lastTrade.price} ${tradeAge}m ago`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
await this.log('🚀 Host-based 24/7 Trading Automation Started');
|
||||||
|
await this.log(`📊 Config: ${this.config.symbol} every ${this.config.intervalMinutes}m, threshold: ${this.config.autoExecuteThreshold}%`);
|
||||||
|
await this.log(`🌐 API Host: ${this.config.apiHost}`);
|
||||||
|
|
||||||
|
await this.runAnalysisCycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const automation = new HostAutomation();
|
||||||
|
automation.start().catch(error => {
|
||||||
|
console.error('💥 Automation failed to start:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
43
lib/paper-trades-storage.js
Normal file
43
lib/paper-trades-storage.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Shared storage for paper trades
|
||||||
|
// In production, this should be replaced with a proper database
|
||||||
|
|
||||||
|
let paperTrades = []
|
||||||
|
let tradeIdCounter = 1
|
||||||
|
|
||||||
|
export function addTrade(trade) {
|
||||||
|
const newTrade = {
|
||||||
|
...trade,
|
||||||
|
id: `PAPER_${Date.now()}_${tradeIdCounter++}`,
|
||||||
|
status: 'OPEN',
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
pnl: 0,
|
||||||
|
fees: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
paperTrades.push(newTrade)
|
||||||
|
console.log(`📄 Paper trade stored: ${newTrade.id} - ${newTrade.side} ${newTrade.symbol} at $${newTrade.entry}`)
|
||||||
|
|
||||||
|
return newTrade
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllTrades() {
|
||||||
|
return paperTrades
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTradeStats() {
|
||||||
|
const totalTrades = paperTrades.length
|
||||||
|
const totalValue = paperTrades.reduce((sum, trade) => {
|
||||||
|
return sum + (trade.side === 'BUY' ? -trade.amount : trade.amount) + trade.pnl
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const buyTrades = paperTrades.filter(t => t.side === 'BUY').length
|
||||||
|
const sellTrades = paperTrades.filter(t => t.side === 'SELL').length
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalTrades,
|
||||||
|
totalValue,
|
||||||
|
buyTrades,
|
||||||
|
sellTrades,
|
||||||
|
paperTrades
|
||||||
|
}
|
||||||
|
}
|
||||||
188
robust-automation.js
Normal file
188
robust-automation.js
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Robust 24/7 Trading Automation
|
||||||
|
* Handles API timeouts and network issues gracefully
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RobustAutomation {
|
||||||
|
constructor() {
|
||||||
|
this.config = {
|
||||||
|
symbol: 'SOLUSD',
|
||||||
|
timeframe: '60',
|
||||||
|
intervalMinutes: 60,
|
||||||
|
autoExecuteThreshold: 60,
|
||||||
|
apiHost: '192.168.0.1:9001',
|
||||||
|
requestTimeout: 30000 // 30 seconds
|
||||||
|
};
|
||||||
|
this.cycleCount = 0;
|
||||||
|
|
||||||
|
this.stats = {
|
||||||
|
startTime: new Date(),
|
||||||
|
totalCycles: 0,
|
||||||
|
totalTrades: 0,
|
||||||
|
successfulCycles: 0,
|
||||||
|
failedCycles: 0,
|
||||||
|
lastSignal: null,
|
||||||
|
lastTrade: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async log(message) {
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
console.log(`[${timestamp}] ${message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async makeRequest(url, options = {}) {
|
||||||
|
try {
|
||||||
|
// Add timeout to all requests
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), this.config.requestTimeout);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
...options,
|
||||||
|
signal: controller.signal
|
||||||
|
});
|
||||||
|
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
if (error.name === 'AbortError') {
|
||||||
|
await this.log(`⏱️ Request timeout: ${url}`);
|
||||||
|
} else {
|
||||||
|
await this.log(`❌ Request failed: ${error.message}`);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async runAnalysisCycle() {
|
||||||
|
this.stats.totalCycles++;
|
||||||
|
await this.log(`🔄 Analysis cycle #${this.stats.totalCycles}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get current technical analysis with timeout
|
||||||
|
await this.log(`📡 Fetching analysis from API...`);
|
||||||
|
const data = await this.makeRequest(`http://${this.config.apiHost}/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`);
|
||||||
|
|
||||||
|
if (data && data.success && data.data && data.data.analysis) {
|
||||||
|
const analysis = data.data.analysis;
|
||||||
|
this.stats.lastSignal = {
|
||||||
|
time: new Date(),
|
||||||
|
recommendation: analysis.recommendation,
|
||||||
|
confidence: analysis.confidence
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.log(`📊 Signal: ${analysis.recommendation} (${analysis.confidence}% confidence)`);
|
||||||
|
|
||||||
|
// Execute trade if confidence is high enough
|
||||||
|
if (analysis.confidence >= this.config.autoExecuteThreshold &&
|
||||||
|
(analysis.recommendation === 'BUY' || analysis.recommendation === 'SELL')) {
|
||||||
|
|
||||||
|
await this.log(`🚀 Executing ${analysis.recommendation} trade with ${analysis.confidence}% confidence`);
|
||||||
|
|
||||||
|
const trade = await this.executeTrade(analysis);
|
||||||
|
if (trade && trade.success) {
|
||||||
|
this.stats.totalTrades++;
|
||||||
|
this.stats.lastTrade = {
|
||||||
|
time: new Date(),
|
||||||
|
type: analysis.recommendation,
|
||||||
|
confidence: analysis.confidence,
|
||||||
|
price: trade.trade?.entry || analysis.entry?.price || 'unknown'
|
||||||
|
};
|
||||||
|
await this.log(`✅ Trade executed successfully: ${analysis.recommendation} at ${trade.trade?.entry || analysis.entry?.price || 'unknown'}`);
|
||||||
|
} else {
|
||||||
|
await this.log(`❌ Trade execution failed`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await this.log(`⏸️ Confidence ${analysis.confidence}% below threshold ${this.config.autoExecuteThreshold}% - holding`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stats.successfulCycles++;
|
||||||
|
} else {
|
||||||
|
await this.log(`❌ No valid analysis data received`);
|
||||||
|
this.stats.failedCycles++;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
await this.log(`❌ Cycle error: ${error.message}`);
|
||||||
|
this.stats.failedCycles++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print stats every cycle
|
||||||
|
await this.printStats();
|
||||||
|
|
||||||
|
// Schedule next cycle
|
||||||
|
const nextCycle = new Date(Date.now() + this.config.intervalMinutes * 60 * 1000);
|
||||||
|
await this.log(`⏰ Next cycle: ${nextCycle.toLocaleTimeString()}`);
|
||||||
|
await this.log(`🔄 Scheduling next cycle in ${this.config.intervalMinutes} minutes...`);
|
||||||
|
|
||||||
|
setTimeout(() => this.runAnalysisCycle(), this.config.intervalMinutes * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeTrade(analysis) {
|
||||||
|
try {
|
||||||
|
await this.log(`💱 Preparing trade data...`);
|
||||||
|
const tradeData = {
|
||||||
|
symbol: this.config.symbol,
|
||||||
|
side: analysis.recommendation,
|
||||||
|
amount: 100, // $100 paper trade
|
||||||
|
entry: analysis.entry?.price || 150, // Use analysis entry price or fallback
|
||||||
|
confidence: analysis.confidence,
|
||||||
|
reasoning: analysis.reasoning || 'Automated trade from analysis',
|
||||||
|
source: 'robust_automation_24x7'
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.log(`📤 Sending trade request...`);
|
||||||
|
const result = await this.makeRequest(`http://${this.config.apiHost}/api/safe-paper-trading/create-trade`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(tradeData)
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
await this.log(`❌ Trade execution error: ${error.message}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async printStats() {
|
||||||
|
const uptime = Math.floor((Date.now() - this.stats.startTime) / 1000 / 60); // minutes
|
||||||
|
const successRate = this.stats.totalCycles > 0 ? Math.round((this.stats.successfulCycles / this.stats.totalCycles) * 100) : 0;
|
||||||
|
|
||||||
|
await this.log(`📈 Stats: ${this.stats.totalCycles} cycles (${successRate}% success), ${this.stats.totalTrades} trades, ${uptime}m uptime`);
|
||||||
|
|
||||||
|
if (this.stats.lastSignal) {
|
||||||
|
const signalAge = Math.floor((Date.now() - this.stats.lastSignal.time) / 1000 / 60);
|
||||||
|
await this.log(`🎯 Last signal: ${this.stats.lastSignal.recommendation} (${this.stats.lastSignal.confidence}%) ${signalAge}m ago`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stats.lastTrade) {
|
||||||
|
const tradeAge = Math.floor((Date.now() - this.stats.lastTrade.time) / 1000 / 60);
|
||||||
|
await this.log(`💰 Last trade: ${this.stats.lastTrade.type} at ${this.stats.lastTrade.price} ${tradeAge}m ago`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
await this.log('🚀 Robust 24/7 Trading Automation Started');
|
||||||
|
await this.log(`📊 Config: ${this.config.symbol} every ${this.config.intervalMinutes}m, threshold: ${this.config.autoExecuteThreshold}%`);
|
||||||
|
await this.log(`🌐 API Host: ${this.config.apiHost}, Timeout: ${this.config.requestTimeout}ms`);
|
||||||
|
|
||||||
|
// Start first cycle
|
||||||
|
await this.runAnalysisCycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the automation
|
||||||
|
const automation = new RobustAutomation();
|
||||||
|
automation.start().catch(error => {
|
||||||
|
console.error('💥 Automation failed to start:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
156
simple-automation.js
Normal file
156
simple-automation.js
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple 24/7 Trading Automation
|
||||||
|
* Focuses on core trading without complex sentiment analysis
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SimpleAutomation {
|
||||||
|
constructor() {
|
||||||
|
this.config = {
|
||||||
|
symbol: 'SOLUSD',
|
||||||
|
timeframe: '60',
|
||||||
|
intervalMinutes: 60,
|
||||||
|
autoExecuteThreshold: 60,
|
||||||
|
apiHost: '192.168.0.1:9001'
|
||||||
|
};
|
||||||
|
this.cycleCount = 0;
|
||||||
|
|
||||||
|
this.stats = {
|
||||||
|
startTime: new Date(),
|
||||||
|
totalCycles: 0,
|
||||||
|
totalTrades: 0,
|
||||||
|
lastSignal: null,
|
||||||
|
lastTrade: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async log(message) {
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
console.log(`[${timestamp}] ${message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async makeRequest(url, options = {}) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, options);
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
await this.log(`❌ Request failed: ${error.message}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async runAnalysisCycle() {
|
||||||
|
this.stats.totalCycles++;
|
||||||
|
await this.log(`🔄 Analysis cycle #${this.stats.totalCycles}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get current technical analysis
|
||||||
|
const data = await this.makeRequest(`http://${this.config.apiHost}/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`);
|
||||||
|
|
||||||
|
if (data && data.success && data.data && data.data.analysis) {
|
||||||
|
const analysis = data.data.analysis;
|
||||||
|
this.stats.lastSignal = {
|
||||||
|
time: new Date(),
|
||||||
|
recommendation: analysis.recommendation,
|
||||||
|
confidence: analysis.confidence
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.log(`📊 Signal: ${analysis.recommendation} (${analysis.confidence}% confidence)`);
|
||||||
|
|
||||||
|
// Execute trade if confidence is high enough
|
||||||
|
if (analysis.confidence >= this.config.autoExecuteThreshold &&
|
||||||
|
(analysis.recommendation === 'BUY' || analysis.recommendation === 'SELL')) {
|
||||||
|
|
||||||
|
await this.log(`🚀 Executing ${analysis.recommendation} trade with ${analysis.confidence}% confidence`);
|
||||||
|
|
||||||
|
const trade = await this.executeTrade(analysis);
|
||||||
|
if (trade && trade.success) {
|
||||||
|
this.stats.totalTrades++;
|
||||||
|
this.stats.lastTrade = {
|
||||||
|
time: new Date(),
|
||||||
|
type: analysis.recommendation,
|
||||||
|
confidence: analysis.confidence,
|
||||||
|
price: trade.trade?.price || 'unknown'
|
||||||
|
};
|
||||||
|
await this.log(`✅ Trade executed successfully: ${analysis.recommendation} at ${trade.trade?.price || 'unknown'}`);
|
||||||
|
} else {
|
||||||
|
await this.log(`❌ Trade execution failed`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await this.log(`⏸️ Confidence ${analysis.confidence}% below threshold ${this.config.autoExecuteThreshold}% - holding`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await this.log(`❌ No valid analysis data received`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
await this.log(`❌ Cycle error: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule next cycle
|
||||||
|
const nextCycle = new Date(Date.now() + this.config.intervalMinutes * 60 * 1000);
|
||||||
|
await this.log(`⏰ Next cycle: ${nextCycle.toLocaleTimeString()}`);
|
||||||
|
|
||||||
|
setTimeout(() => this.runAnalysisCycle(), this.config.intervalMinutes * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeTrade(analysis) {
|
||||||
|
try {
|
||||||
|
const tradeData = {
|
||||||
|
symbol: this.config.symbol,
|
||||||
|
side: analysis.recommendation,
|
||||||
|
amount: 100, // $100 paper trade
|
||||||
|
entry: analysis.currentPrice || 150, // Fallback price
|
||||||
|
confidence: analysis.confidence,
|
||||||
|
reasoning: analysis.reasoning,
|
||||||
|
source: 'simple_automation_24x7'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await this.makeRequest(`http://${this.config.apiHost}/api/safe-paper-trading/create-trade`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(tradeData)
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
await this.log(`❌ Trade execution error: ${error.message}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async printStats() {
|
||||||
|
const uptime = Math.floor((Date.now() - this.stats.startTime) / 1000 / 60); // minutes
|
||||||
|
await this.log(`📈 Stats: ${this.stats.totalCycles} cycles, ${this.stats.totalTrades} trades, ${uptime}m uptime`);
|
||||||
|
|
||||||
|
if (this.stats.lastSignal) {
|
||||||
|
const signalAge = Math.floor((Date.now() - this.stats.lastSignal.time) / 1000 / 60);
|
||||||
|
await this.log(`🎯 Last signal: ${this.stats.lastSignal.recommendation} (${this.stats.lastSignal.confidence}%) ${signalAge}m ago`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stats.lastTrade) {
|
||||||
|
const tradeAge = Math.floor((Date.now() - this.stats.lastTrade.time) / 1000 / 60);
|
||||||
|
await this.log(`💰 Last trade: ${this.stats.lastTrade.type} at ${this.stats.lastTrade.price} ${tradeAge}m ago`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
await this.log('🚀 Simple 24/7 Trading Automation Started');
|
||||||
|
await this.log(`📊 Config: ${this.config.symbol} every ${this.config.intervalMinutes}m, threshold: ${this.config.autoExecuteThreshold}%`);
|
||||||
|
|
||||||
|
// Print stats every 30 minutes
|
||||||
|
setInterval(() => this.printStats(), 30 * 60 * 1000);
|
||||||
|
|
||||||
|
// Start first cycle
|
||||||
|
await this.runAnalysisCycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the automation
|
||||||
|
const automation = new SimpleAutomation();
|
||||||
|
automation.start().catch(error => {
|
||||||
|
console.error('💥 Automation failed to start:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
11
simple-automation.log
Normal file
11
simple-automation.log
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
nohup: ignoring input
|
||||||
|
[2025-08-07T14:03:02.012Z] 🚀 Simple 24/7 Trading Automation Started
|
||||||
|
[2025-08-07T14:03:02.016Z] 📊 Config: SOLUSD every 60m, threshold: 60%
|
||||||
|
[2025-08-07T14:03:02.016Z] 🔄 Analysis cycle #1
|
||||||
|
[2025-08-07T14:04:44.103Z] 📊 Signal: BUY (85% confidence)
|
||||||
|
[2025-08-07T14:04:44.103Z] 🚀 Executing BUY trade with 85% confidence
|
||||||
|
[2025-08-07T14:04:44.120Z] ✅ Trade executed successfully: BUY at unknown
|
||||||
|
[2025-08-07T14:04:44.166Z] ⏰ Next cycle: 5:04:44 PM
|
||||||
|
[2025-08-07T14:33:02.116Z] 📈 Stats: 1 cycles, 1 trades, 30m uptime
|
||||||
|
[2025-08-07T14:33:02.116Z] 🎯 Last signal: BUY (85%) 28m ago
|
||||||
|
[2025-08-07T14:33:02.116Z] 💰 Last trade: BUY at unknown 28m ago
|
||||||
41
trade-monitor.js
Normal file
41
trade-monitor.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
// Trade Monitor - Track trade creation and persistence
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
async function checkTrades() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('http://localhost:9001/api/safe-paper-trading/trades');
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
const logEntry = {
|
||||||
|
timestamp,
|
||||||
|
totalTrades: data.totalTrades,
|
||||||
|
trades: data.trades.map(t => ({
|
||||||
|
id: t.id,
|
||||||
|
side: t.side,
|
||||||
|
source: t.source,
|
||||||
|
createdAt: t.createdAt
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Log to file
|
||||||
|
fs.appendFileSync('trade-monitor.log', JSON.stringify(logEntry) + '\n');
|
||||||
|
|
||||||
|
console.log(`[${timestamp}] Trades: ${data.totalTrades}`);
|
||||||
|
if (data.totalTrades > 0) {
|
||||||
|
data.trades.forEach(trade => {
|
||||||
|
console.log(` - ${trade.id}: ${trade.side} (${trade.source})`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[${new Date().toISOString()}] Error checking trades:`, error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check every 30 seconds
|
||||||
|
console.log('🔍 Trade Monitor Started - Checking every 30 seconds');
|
||||||
|
setInterval(checkTrades, 30000);
|
||||||
|
checkTrades(); // Initial check
|
||||||
68
trade-monitor.log
Normal file
68
trade-monitor.log
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{"timestamp":"2025-08-07T14:13:56.843Z","totalTrades":1,"trades":[{"id":"PAPER_1754575919891_1","side":"BUY","source":"manual_verification","createdAt":"2025-08-07T14:11:59.891Z"}]}
|
||||||
|
{"timestamp":"2025-08-07T14:14:26.816Z","totalTrades":1,"trades":[{"id":"PAPER_1754575919891_1","side":"BUY","source":"manual_verification","createdAt":"2025-08-07T14:11:59.891Z"}]}
|
||||||
|
{"timestamp":"2025-08-07T14:14:56.839Z","totalTrades":1,"trades":[{"id":"PAPER_1754575919891_1","side":"BUY","source":"manual_verification","createdAt":"2025-08-07T14:11:59.891Z"}]}
|
||||||
|
{"timestamp":"2025-08-07T14:15:26.872Z","totalTrades":1,"trades":[{"id":"PAPER_1754575919891_1","side":"BUY","source":"manual_verification","createdAt":"2025-08-07T14:11:59.891Z"}]}
|
||||||
|
{"timestamp":"2025-08-07T14:15:56.890Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:16:26.924Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:16:56.940Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:17:26.971Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:17:57.003Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:18:27.030Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:18:57.054Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:19:27.081Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:19:57.108Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:20:27.135Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:20:57.165Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:21:27.185Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:21:57.209Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:22:27.238Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:22:57.250Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:23:27.273Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:23:57.300Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:24:27.321Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:24:57.350Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:25:27.376Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:25:57.391Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:26:27.427Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:26:57.452Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:27:27.478Z","totalTrades":1,"trades":[{"id":"PAPER_1754576825487_1","side":"BUY","source":"manual_test","createdAt":"2025-08-07T14:27:05.487Z"}]}
|
||||||
|
{"timestamp":"2025-08-07T14:27:57.505Z","totalTrades":1,"trades":[{"id":"PAPER_1754576825487_1","side":"BUY","source":"manual_test","createdAt":"2025-08-07T14:27:05.487Z"}]}
|
||||||
|
{"timestamp":"2025-08-07T14:28:27.993Z","totalTrades":1,"trades":[{"id":"PAPER_1754576825487_1","side":"BUY","source":"manual_test","createdAt":"2025-08-07T14:27:05.487Z"}]}
|
||||||
|
{"timestamp":"2025-08-07T14:28:57.560Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:29:27.580Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:29:57.581Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:30:27.597Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:30:57.626Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:31:27.653Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:31:57.674Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:32:27.704Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:32:57.904Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:33:27.749Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:33:57.802Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:34:27.835Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:34:57.834Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:35:27.857Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:35:57.894Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:36:27.939Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:36:57.944Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:37:27.969Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:37:57.998Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:38:28.041Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:38:58.049Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:39:28.056Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:39:58.084Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:40:28.109Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:40:58.137Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:41:28.160Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:41:58.182Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:42:28.209Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:42:58.233Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:43:28.247Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:43:58.260Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:44:28.286Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:44:58.303Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:45:28.336Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:45:58.368Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:46:28.386Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:46:58.411Z","totalTrades":0,"trades":[]}
|
||||||
|
{"timestamp":"2025-08-07T14:47:28.439Z","totalTrades":0,"trades":[]}
|
||||||
41
trading_alerts.log
Normal file
41
trading_alerts.log
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
nohup: ignoring input
|
||||||
|
[Wed Aug 6 20:59:50 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Wed Aug 6 22:00:42 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Wed Aug 6 23:01:43 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 00:02:47 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 01:03:55 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 02:05:05 CEST 2025] Checking for trading signals...
|
||||||
|
No strong signal (HOLD at 75%)
|
||||||
|
[Thu Aug 7 03:06:19 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 04:07:28 CEST 2025] Checking for trading signals...
|
||||||
|
No strong signal (HOLD at 75%)
|
||||||
|
[Thu Aug 7 05:08:39 CEST 2025] Checking for trading signals...
|
||||||
|
No strong signal (HOLD at 75%)
|
||||||
|
[Thu Aug 7 06:09:53 CEST 2025] Checking for trading signals...
|
||||||
|
No strong signal (HOLD at 75%)
|
||||||
|
[Thu Aug 7 07:11:01 CEST 2025] Checking for trading signals...
|
||||||
|
No strong signal (HOLD at 75%)
|
||||||
|
[Thu Aug 7 08:12:16 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 09:13:36 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 10:14:59 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 11:16:26 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 12:17:52 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 13:19:20 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 14:20:52 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 15:22:25 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
|
[Thu Aug 7 16:24:00 CEST 2025] Checking for trading signals...
|
||||||
|
SIGNAL: BUY at 85% confidence - Execute trade manually
|
||||||
Reference in New Issue
Block a user