/home/devscfvi/app.devsquantum.com/api.php
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type');
require_once 'config.php';
$pdo = getDBConnection();
// Self-healing migration: add trade_mode column if not exists
try {
$pdo->exec("ALTER TABLE crypto_trades ADD COLUMN trade_mode VARCHAR(10) NOT NULL DEFAULT 'crypto'");
} catch (\PDOException $e) {
// Column already exists or unsupported — ignore
}
// ============================================
// HELPER FUNCTIONS
// ============================================
function sendJSON($data) {
echo json_encode($data);
exit;
}
function getInput() {
return json_decode(file_get_contents('php://input'), true);
}
// ============================================
// GET REQUESTS
// ============================================
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$action = $_GET['action'] ?? '';
switch($action) {
case 'getTrades':
$mode = $_GET['mode'] ?? 'crypto';
$stmt = $pdo->prepare("SELECT * FROM crypto_trades WHERE trade_mode = ? ORDER BY created_at DESC");
$stmt->execute([$mode]);
$trades = $stmt->fetchAll();
sendJSON(['success' => true, 'trades' => $trades]);
case 'getStats':
$mode = $_GET['mode'] ?? 'crypto';
$stmt = $pdo->prepare("
SELECT
COUNT(*) as total_trades,
SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
SUM(CASE WHEN status = 'loss' THEN 1 ELSE 0 END) as losses,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_trades,
SUM(CASE WHEN status = 'win' THEN profit_amount WHEN status = 'loss' THEN -loss_amount ELSE 0 END) as total_pnl,
AVG(reward_risk_ratio) as avg_rr,
ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 / NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate,
MAX(CASE WHEN status = 'win' THEN profit_amount ELSE 0 END) as best_win,
MAX(CASE WHEN status = 'loss' THEN loss_amount ELSE 0 END) as worst_loss
FROM crypto_trades
WHERE trade_mode = ?
");
$stmt->execute([$mode]);
$stats = $stmt->fetch();
sendJSON(['success' => true, 'stats' => $stats]);
case 'getAdvancedAnalytics':
$mode = $_GET['mode'] ?? 'crypto';
// Performance by category (mode-filtered inline query)
$stmt = $pdo->prepare("
SELECT
trade_category as category,
COUNT(*) as total,
SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
SUM(CASE WHEN status = 'loss' THEN 1 ELSE 0 END) as losses,
ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 /
NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate,
SUM(CASE WHEN status = 'win' THEN profit_amount WHEN status = 'loss' THEN -loss_amount ELSE 0 END) as net_pnl
FROM crypto_trades
WHERE trade_category IS NOT NULL AND trade_mode = ?
GROUP BY trade_category
");
$stmt->execute([$mode]);
$byCategory = $stmt->fetchAll();
// Performance by coin/asset (mode-filtered)
$stmt = $pdo->prepare("
SELECT
coin,
COUNT(*) as total,
SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
SUM(CASE WHEN status = 'loss' THEN 1 ELSE 0 END) as losses,
ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 /
NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate,
SUM(CASE WHEN status = 'win' THEN profit_amount WHEN status = 'loss' THEN -loss_amount ELSE 0 END) as net_pnl
FROM crypto_trades
WHERE trade_mode = ?
GROUP BY coin
ORDER BY net_pnl DESC
");
$stmt->execute([$mode]);
$byCoin = $stmt->fetchAll();
// Emotion analysis
$stmt = $pdo->prepare("
SELECT
emotion,
COUNT(*) as count,
SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as win_rate
FROM crypto_trades
WHERE emotion IS NOT NULL AND status IN ('win', 'loss') AND trade_mode = ?
GROUP BY emotion
");
$stmt->execute([$mode]);
$byEmotion = $stmt->fetchAll();
// Time-based analysis (by hour)
$stmt = $pdo->prepare("
SELECT
HOUR(created_at) as hour,
COUNT(*) as trades,
SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 /
NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate
FROM crypto_trades
WHERE status IN ('win', 'loss') AND trade_mode = ?
GROUP BY HOUR(created_at)
ORDER BY hour
");
$stmt->execute([$mode]);
$byHour = $stmt->fetchAll();
// Consecutive wins/losses (streaks)
$stmt = $pdo->prepare("
SELECT status, created_at
FROM crypto_trades
WHERE status IN ('win', 'loss') AND trade_mode = ?
ORDER BY created_at DESC
LIMIT 50
");
$stmt->execute([$mode]);
$recentTrades = $stmt->fetchAll();
$currentStreak = 0;
$streakType = null;
$maxWinStreak = 0;
$maxLossStreak = 0;
$currentWinStreak = 0;
$currentLossStreak = 0;
foreach ($recentTrades as $trade) {
if ($streakType === null) {
$streakType = $trade['status'];
$currentStreak = 1;
} elseif ($trade['status'] === $streakType) {
$currentStreak++;
} else {
if ($streakType === 'win') {
$maxWinStreak = max($maxWinStreak, $currentStreak);
} else {
$maxLossStreak = max($maxLossStreak, $currentStreak);
}
$streakType = $trade['status'];
$currentStreak = 1;
}
}
if ($streakType === 'win') {
$maxWinStreak = max($maxWinStreak, $currentStreak);
$currentWinStreak = $currentStreak;
} else {
$maxLossStreak = max($maxLossStreak, $currentStreak);
$currentLossStreak = $currentStreak;
}
sendJSON([
'success' => true,
'analytics' => [
'byCategory' => $byCategory,
'byCoin' => $byCoin,
'byEmotion' => $byEmotion,
'byHour' => $byHour,
'streaks' => [
'current_win_streak' => $currentWinStreak,
'current_loss_streak' => $currentLossStreak,
'max_win_streak' => $maxWinStreak,
'max_loss_streak' => $maxLossStreak
]
]
]);
case 'getMistakes':
$stmt = $pdo->query("SELECT * FROM v_mistake_analysis");
$mistakes = $stmt->fetchAll();
$stmt = $pdo->query("SELECT * FROM trade_mistakes WHERE is_active = 1 ORDER BY category, mistake_name");
$mistakeTypes = $stmt->fetchAll();
sendJSON(['success' => true, 'mistakes' => $mistakes, 'mistakeTypes' => $mistakeTypes]);
case 'getGoals':
$stmt = $pdo->query("
SELECT * FROM trading_goals
WHERE period_end >= CURDATE()
ORDER BY period_start DESC
");
$goals = $stmt->fetchAll();
sendJSON(['success' => true, 'goals' => $goals]);
case 'getGoalProgress':
$goalId = $_GET['goalId'] ?? null;
if (!$goalId) {
sendJSON(['success' => false, 'error' => 'Goal ID required']);
}
$stmt = $pdo->prepare("SELECT * FROM trading_goals WHERE id = ?");
$stmt->execute([$goalId]);
$goal = $stmt->fetch();
if (!$goal) {
sendJSON(['success' => false, 'error' => 'Goal not found']);
}
// Get trades in this period
$stmt = $pdo->prepare("
SELECT
COUNT(*) as total_trades,
SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) as wins,
SUM(CASE WHEN status = 'loss' THEN 1 ELSE 0 END) as losses,
SUM(CASE WHEN status = 'win' THEN profit_amount WHEN status = 'loss' THEN -loss_amount ELSE 0 END) as total_pnl,
ROUND(SUM(CASE WHEN status = 'win' THEN 1 ELSE 0 END) * 100.0 /
NULLIF(SUM(CASE WHEN status IN ('win', 'loss') THEN 1 ELSE 0 END), 0), 2) as win_rate,
AVG(reward_risk_ratio) as avg_rr
FROM crypto_trades
WHERE DATE(created_at) BETWEEN ? AND ?
");
$stmt->execute([$goal['period_start'], $goal['period_end']]);
$progress = $stmt->fetch();
sendJSON(['success' => true, 'goal' => $goal, 'progress' => $progress]);
case 'getJournalEntries':
$limit = $_GET['limit'] ?? 30;
$stmt = $pdo->prepare("
SELECT * FROM trading_journal_entries
ORDER BY entry_date DESC
LIMIT ?
");
$stmt->execute([$limit]);
$entries = $stmt->fetchAll();
sendJSON(['success' => true, 'entries' => $entries]);
break;
case 'getBudget':
$stmt = $pdo->query("SELECT budget FROM user_budget ORDER BY id DESC LIMIT 1");
$result = $stmt->fetch();
sendJSON(['success' => true, 'budget' => $result ? $result['budget'] : null]);
break;
case 'getBudgetTransactions':
$stmt = $pdo->query("
SELECT * FROM budget_transactions
ORDER BY created_at DESC
LIMIT 50
");
$transactions = $stmt->fetchAll();
sendJSON(['success' => true, 'transactions' => $transactions]);
break;
case 'getFavoriteCoins':
$stmt = $pdo->query("SELECT coins FROM favorite_coins ORDER BY id DESC LIMIT 1");
$result = $stmt->fetch();
$coins = $result ? json_decode($result['coins']) : ['BTC', 'ETH', 'SOL', 'SUI', 'XRP', 'ADA', 'LINK'];
sendJSON(['success' => true, 'coins' => $coins]);
break;
default:
sendJSON(['success' => false, 'error' => 'Invalid action']);
}
}
// ============================================
// POST REQUESTS
// ============================================
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input = getInput();
$action = $input['action'] ?? '';
switch($action) {
case 'saveTrade':
$trade = $input['trade'];
$stmt = $pdo->prepare("
INSERT INTO crypto_trades
(coin, position_size, entry_price, stop_loss_percent, take_profit_percent,
quantity, sl_price, tp_price, loss_amount, profit_amount, reward_risk_ratio,
fees, order_type, comment, trade_category, emotion, discipline_score,
mistake_type, lesson_learned, pre_trade_plan, entry_screenshot, trade_mode)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$stmt->execute([
$trade['coin'],
$trade['positionSize'],
$trade['entryPrice'],
$trade['stopLossPercent'],
$trade['takeProfitPercent'],
$trade['quantity'],
$trade['slPrice'],
$trade['tpPrice'],
$trade['lossAmount'],
$trade['profitAmount'],
$trade['rewardRiskRatio'],
$trade['fees'],
$trade['orderType'] ?? 'market',
$trade['comment'] ?? '',
$trade['category'] ?? null,
$trade['emotion'] ?? null,
$trade['disciplineScore'] ?? null,
$trade['mistakeType'] ?? null,
$trade['lessonLearned'] ?? null,
$trade['preTradePlan'] ?? null,
$trade['entryScreenshot'] ?? null,
$trade['tradeMode'] ?? 'crypto'
]);
$tradeId = $pdo->lastInsertId();
// Save tags if provided
if (!empty($trade['tags'])) {
$stmt = $pdo->prepare("INSERT INTO trade_tags (trade_id, tag) VALUES (?, ?)");
foreach ($trade['tags'] as $tag) {
$stmt->execute([$tradeId, $tag]);
}
}
sendJSON(['success' => true, 'tradeId' => $tradeId]);
case 'updateTradeStatus':
$stmt = $pdo->prepare("UPDATE crypto_trades SET status = ?, comment = ? WHERE id = ?");
$stmt->execute([$input['status'], $input['comment'] ?? '', $input['id']]);
sendJSON(['success' => true]);
case 'updateTradePrices':
$id = $input['id'];
$slPrice = $input['slPrice'];
$tpPrice = $input['tpPrice'];
// Get the trade to recalculate values
$stmt = $pdo->prepare("SELECT * FROM crypto_trades WHERE id = ?");
$stmt->execute([$id]);
$trade = $stmt->fetch();
if ($trade) {
$entry = floatval($trade['entry_price']);
$position = floatval($trade['position_size']);
$quantity = floatval($trade['quantity']);
// Recalculate percentages
$slPercent = (($entry - floatval($slPrice)) / $entry) * 100;
$tpPercent = ((floatval($tpPrice) - $entry) / $entry) * 100;
// Recalculate loss and profit amounts
$slSellValue = $quantity * floatval($slPrice);
$slSellFee = $slSellValue * 0.001;
$lossAmount = $position - ($slSellValue - $slSellFee);
$tpSellValue = $quantity * floatval($tpPrice);
$tpSellFee = $tpSellValue * 0.001;
$profitAmount = ($tpSellValue - $tpSellFee) - $position;
$rewardRiskRatio = $profitAmount / $lossAmount;
$stmt = $pdo->prepare("
UPDATE crypto_trades
SET sl_price = ?, tp_price = ?,
stop_loss_percent = ?, take_profit_percent = ?,
loss_amount = ?, profit_amount = ?,
reward_risk_ratio = ?
WHERE id = ?
");
$stmt->execute([
$slPrice,
$tpPrice,
round($slPercent, 2),
round($tpPercent, 2),
round($lossAmount, 2),
round($profitAmount, 2),
round($rewardRiskRatio, 2),
$id
]);
}
sendJSON(['success' => true]);
case 'updateTradeReview':
$stmt = $pdo->prepare("
UPDATE crypto_trades
SET post_trade_review = ?, emotion = ?, discipline_score = ?,
mistake_type = ?, lesson_learned = ?, exit_screenshot = ?
WHERE id = ?
");
$stmt->execute([
$input['review'] ?? '',
$input['emotion'] ?? null,
$input['disciplineScore'] ?? null,
$input['mistakeType'] ?? null,
$input['lessonLearned'] ?? '',
$input['exitScreenshot'] ?? null,
$input['id']
]);
sendJSON(['success' => true]);
break;
case 'closeTradeWithPnL':
$tradeId = $input['id'];
$status = $input['status']; // 'win' or 'loss'
$actualExitPrice = $input['actualExitPrice'];
$actualPnl = $input['actualPnl'];
// 1. Get trade details
$stmt = $pdo->prepare("SELECT coin FROM crypto_trades WHERE id = ?");
$stmt->execute([$tradeId]);
$trade = $stmt->fetch();
if (!$trade) {
sendJSON(['success' => false, 'error' => 'Trade not found']);
break;
}
// 2. Update trade with result
$stmt = $pdo->prepare("
UPDATE crypto_trades
SET status = ?,
actual_exit_price = ?,
actual_pnl = ?
WHERE id = ?
");
$stmt->execute([$status, $actualExitPrice, $actualPnl, $tradeId]);
// 3. Create budget transaction
$description = "Trade P&L: {$trade['coin']} - " . strtoupper($status);
$transType = ($actualPnl >= 0) ? 'deposit' : 'withdrawal';
$transAmount = abs($actualPnl);
$stmt = $pdo->prepare("
INSERT INTO budget_transactions (transaction_type, amount, description)
VALUES (?, ?, ?)
");
$stmt->execute([$transType, $transAmount, $description]);
// 4. Update budget
$budgetStmt = $pdo->query("SELECT budget FROM user_budget ORDER BY id DESC LIMIT 1");
$budgetResult = $budgetStmt->fetch();
$currentBudget = $budgetResult ? floatval($budgetResult['budget']) : 0;
$newBudget = $currentBudget + floatval($actualPnl); // Add (positive) or subtract (negative)
$pdo->query("DELETE FROM user_budget");
$updateStmt = $pdo->prepare("INSERT INTO user_budget (budget) VALUES (?)");
$updateStmt->execute([$newBudget]);
sendJSON(['success' => true, 'newBudget' => $newBudget]);
break;
case 'deleteTrade':
$stmt = $pdo->prepare("DELETE FROM crypto_trades WHERE id = ?");
$stmt->execute([$input['id']]);
sendJSON(['success' => true]);
case 'saveGoal':
$stmt = $pdo->prepare("
INSERT INTO trading_goals
(goal_type, target_profit, target_win_rate, max_daily_loss,
min_risk_reward, period_start, period_end, notes)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
");
$stmt->execute([
$input['goalType'],
$input['targetProfit'] ?? null,
$input['targetWinRate'] ?? null,
$input['maxDailyLoss'] ?? null,
$input['minRiskReward'] ?? null,
$input['periodStart'],
$input['periodEnd'],
$input['notes'] ?? ''
]);
sendJSON(['success' => true, 'goalId' => $pdo->lastInsertId()]);
case 'deleteGoal':
$stmt = $pdo->prepare("DELETE FROM trading_goals WHERE id = ?");
$stmt->execute([$input['id']]);
sendJSON(['success' => true]);
case 'saveJournalEntry':
$stmt = $pdo->prepare("
INSERT INTO trading_journal_entries
(entry_date, market_condition, overall_emotion, what_went_well,
what_went_wrong, lessons_learned, tomorrow_focus, energy_level)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
market_condition = VALUES(market_condition),
overall_emotion = VALUES(overall_emotion),
what_went_well = VALUES(what_went_well),
what_went_wrong = VALUES(what_went_wrong),
lessons_learned = VALUES(lessons_learned),
tomorrow_focus = VALUES(tomorrow_focus),
energy_level = VALUES(energy_level)
");
$stmt->execute([
$input['entryDate'],
$input['marketCondition'] ?? null,
$input['overallEmotion'] ?? null,
$input['whatWentWell'] ?? '',
$input['whatWentWrong'] ?? '',
$input['lessonsLearned'] ?? '',
$input['tomorrowFocus'] ?? '',
$input['energyLevel'] ?? null
]);
sendJSON(['success' => true]);
case 'saveBudget':
$pdo->query("DELETE FROM user_budget");
$stmt = $pdo->prepare("INSERT INTO user_budget (budget) VALUES (?)");
$stmt->execute([$input['budget']]);
sendJSON(['success' => true]);
case 'addBudgetTransaction':
// Add transaction
$stmt = $pdo->prepare("
INSERT INTO budget_transactions (transaction_type, amount, description)
VALUES (?, ?, ?)
");
$stmt->execute([
$input['type'],
$input['amount'],
$input['description'] ?? null
]);
// Update budget
$currentBudget = 0;
$budgetStmt = $pdo->query("SELECT budget FROM user_budget ORDER BY id DESC LIMIT 1");
$budgetResult = $budgetStmt->fetch();
if ($budgetResult) {
$currentBudget = floatval($budgetResult['budget']);
}
$newBudget = $input['type'] === 'deposit'
? $currentBudget + floatval($input['amount'])
: $currentBudget - floatval($input['amount']);
$pdo->query("DELETE FROM user_budget");
$updateStmt = $pdo->prepare("INSERT INTO user_budget (budget) VALUES (?)");
$updateStmt->execute([$newBudget]);
sendJSON(['success' => true, 'newBudget' => $newBudget]);
break;
case 'saveFavoriteCoins':
$coins = json_encode($input['coins']);
$pdo->query("DELETE FROM favorite_coins");
$stmt = $pdo->prepare("INSERT INTO favorite_coins (coins) VALUES (?)");
$stmt->execute([$coins]);
sendJSON(['success' => true]);
break;
case 'bulkImportTrades':
$trades = $input['trades'] ?? [];
$mode = $input['mode'] ?? 'crypto';
$imported = 0;
$errors = [];
$stmt = $pdo->prepare("
INSERT INTO crypto_trades
(coin, position_size, entry_price, stop_loss_percent, take_profit_percent,
quantity, sl_price, tp_price, loss_amount, profit_amount, reward_risk_ratio,
fees, order_type, comment, trade_category, emotion, discipline_score,
mistake_type, lesson_learned, status, trade_mode)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
foreach ($trades as $i => $t) {
try {
$stmt->execute([
$t['coin'] ?? '',
$t['positionSize'] ?? 0,
$t['entryPrice'] ?? 0,
$t['stopLossPercent'] ?? 0,
$t['takeProfitPercent'] ?? 0,
$t['quantity'] ?? 0,
$t['slPrice'] ?? 0,
$t['tpPrice'] ?? 0,
$t['lossAmount'] ?? 0,
$t['profitAmount'] ?? 0,
$t['rewardRiskRatio'] ?? 0,
$t['fees'] ?? 0,
$t['orderType'] ?? 'market',
$t['comment'] ?? '',
$t['category'] ?? null,
$t['emotion'] ?? null,
$t['disciplineScore'] ?? null,
$t['mistakeType'] ?? null,
$t['lessonLearned'] ?? null,
$t['status'] ?? 'pending',
$mode
]);
$imported++;
} catch (\PDOException $e) {
$errors[] = "Row $i: " . $e->getMessage();
}
}
sendJSON(['success' => true, 'imported' => $imported, 'errors' => $errors]);
break;
default:
sendJSON(['success' => false, 'error' => 'Invalid action']);
}
}
sendJSON(['success' => false, 'error' => 'Invalid request method']);
?>