MetaMiner Debug Test
==================================================
1. PHP Version Check:
PHP Version: 8.1.33
✅ PHP version OK
2. Config File Check:
✅ config.php exists
3. Loading Config:
✅ Config loaded successfully
Database: nvdaxcom_galliumhash_metabuilder
Username: nvdaxcom_galliumhash_metabuilder_user
4. Core Files Check:
✅ engine/core.php
✅ engine/quantitative/quantitative-library.php
✅ transmutations/market-oracle.php
✅ transmutations/pool-strategist.php
✅ transmutations/mempool-intelligence.php
5. Database Connection Test:
✅ Database connection successful
6. Database Tables Check:
✅ blocks: 352 rows
✅ mempool_state: 805 rows
✅ network_stats: 791 rows
✅ pools: 28 rows
7. Loading Core Engine:
✅ core.php loaded
8. Initializing MetaMiner:
class PoolStrategist {
private $db;
private $config;
// Bitcoin constants
private const BLOCK_REWARD = 3.125; // Current BTC per block (post-2024 halving)
private const BLOCKS_PER_DAY = 144;
private const DIFFICULTY_ADJUSTMENT_BLOCKS = 2016;
public function __construct($database, $config = []) {
$this->db = $database;
$this->config = array_merge([
'profitability_window' => 30, // Days for profitability calculation
'pool_comparison_period' => 7, // Days for pool comparison
'ev_confidence_threshold' => 0.70,
'switching_cost_threshold' => 0.02 // Minimum 2% advantage to switch
], $config);
}
/**
* POOL EXPECTED VALUE RANKINGS
* Calculates EV for 1 TH/s over next 24 hours for each pool
*/
private function rankPoolsByEV(): array {
$pools = $this->fetchPoolData();
$networkHashrate = $this->getNetworkHashrate();
$btcPrice = $this->getCurrentBTCPrice();
if (empty($pools)) {
return ['rankings' => [], 'status' => 'no_data'];
}
$rankings = [];
foreach ($pools as $pool) {
$ev = $this->calculatePoolEV($pool, $networkHashrate, $btcPrice);
$poolHashrate = ($pool['hash_rate_ehs'] ?? 0) * 1e18;
$hashrateShare = $networkHashrate > 0 ? ($poolHashrate / $networkHashrate * 100) : 0;
$rankings[] = [
'pool_name' => $pool['pool_name'] ?? 'Unknown Pool',
'hash_rate_ehs' => $pool['hash_rate_ehs'] ?? 0,
'hashrate_share_percent' => round($hashrateShare, 3),
'ev_24h_usd' => $ev['ev_24h_usd'],
'score' => $ev['score'],
'confidence' => $ev['confidence'],
'risk_factors' => $ev['risk_factors']
];
}
// Sort by EV (highest first)
usort($rankings, function($a, $b) {
return $b['ev_24h_usd'] <=> $a['ev_24h_usd'];
});
// Add rankings
foreach ($rankings as $i => &$pool) {
$pool['rank'] = $i + 1;
}
return ['rankings' => $rankings, 'status' => 'success'];
}
private function calculatePoolEV(array $pool, float $networkHashrate, float $btcPrice): array {
// Base calculation: proportion of network hashrate
$dailyBTCReward = self::BLOCK_REWARD * self::BLOCKS_PER_DAY;
// Convert pool hashrate from EH/s to H/s (if it exists)
$poolHashrate = ($pool['hash_rate_ehs'] ?? 0) * 1e18;
// Prevent division by zero
if ($poolHashrate <= 0 || $networkHashrate <= 0) {
return [
'ev_24h_usd' => 0,
'score' => 0,
'confidence' => 0,
'risk_factors' => ['insufficient_data']
];
}
$poolShare = $networkHashrate > 0 ? $poolHashrate / $networkHashrate : 0;
// Expected BTC per TH/s per day (before adjustments)
// 🔧 FIXED: Added division by zero protection
$baseBTCPerTH = $poolHashrate > 0 ? ($poolShare * $dailyBTCReward) / ($poolHashrate / 1e12) : 0; // Convert to TH
// Adjustment 1: Pool fee
$poolFee = $pool['pool_fee'] ?? $pool['fee'] ?? 2.0; // Default 2% if not specified
$afterFee = $baseBTCPerTH * (1 - $poolFee / 100);
// Adjustment 2: Payment method variance
$paymentMethod = $pool['payment_method'] ?? 'PPLNS';
$luck = $pool['luck_percentage'] ?? $pool['luck'] ?? 100;
$paymentMultiplier = $this->getPaymentMethodMultiplier($paymentMethod, $luck);
$afterPaymentMethod = $afterFee * $paymentMultiplier;
// Adjustment 3: Orphan risk (blocks that don't get included)
$orphanRate = $this->calculateOrphanRisk($pool);
$afterOrphanRisk = $afterPaymentMethod * (1 - $orphanRate / 100);
// Convert to 24-hour period
$btcPer24h = $afterOrphanRisk / 24;
$usdPer24h = $btcPer24h * $btcPrice;
// Score: weighted composite (higher is better)
// 🔧 FIXED: Added division by zero protection
$score = $baseBTCPerTH > 0 ? ($usdPer24h / $baseBTCPerTH) * 100 : 0;
return [
'ev_24h_usd' => round($usdPer24h, 4),
'score' => round($score, 2),
'confidence' => $this->calculateEVConfidence($pool),
'risk_factors' => $this->identifyPoolRisks($pool),
'base_calculations' => [
'pool_share_percent' => round($poolShare * 100, 4),
'base_btc_per_th' => round($baseBTCPerTH, 8),
'pool_fee_percent' => $poolFee,
'payment_multiplier' => $paymentMultiplier,
'orphan_risk_percent' => $orphanRate
]
];
}
private function calculateEVConfidence(array $pool): float {
$confidence = 60.0; // Base confidence
// Higher if pool has recent data
if (($pool['last_update'] ?? '') > date('Y-m-d H:i:s', strtotime('-1 hour'))) {
$confidence += 20;
}
// Higher if pool has sufficient hashrate
$hashrate = $pool['hash_rate_ehs'] ?? 0;
if ($hashrate > 1000) $confidence += 15;
elseif ($hashrate > 100) $confidence += 10;
// Higher if consistent payment method
if (($pool['payment_method'] ?? '') === 'PPS') {
$confidence += 5;
}
return min(95, $confidence);
}
private function identifyPoolRisks(array $pool): array {
$risks = [];
// Orphan risk
if ($this->calculateOrphanRisk($pool) > 0.5) {
$risks[] = 'high_orphan_risk';
}
// Fee risk
$fee = $pool['pool_fee'] ?? $pool['fee'] ?? 2.0;
if ($fee > 3.0) {
$risks[] = 'high_pool_fee';
}
// Payment method risk
if (($pool['payment_method'] ?? 'PPLNS') !== 'PPS') {
$risks[] = 'payment_variance';
}
return $risks;
}
/**
* HARDWARE PROFITABILITY ANALYSIS
*/
public function getHardwareProfitability(): array {
$difficulty = $this->getCurrentDifficulty();
$btcPrice = $this->getCurrentBTCPrice();
$powerCost = $this->config['power_cost_kwh'] ?? 0.10; // $/kWh
// Forecast difficulty adjustment
$difficultyForecast = $this->projectDifficultyAdjustment();
// Check if we have valid forecast data
if (isset($difficultyForecast['status']) && $difficultyForecast['status'] === 'insufficient_data') {
return ['status' => 'insufficient_data', 'reason' => 'Not enough block data for difficulty forecast'];
}
// Use forecast difficulty if available, otherwise current
$nextDifficulty = $difficultyForecast['predicted_difficulty'] ?? $difficulty;
// Calculate profitability for common hardware
$hardwareModels = $this->getHardwareModels();
$profitabilityByModel = [];
foreach ($hardwareModels as $model) {
$current = $this->calculateMinerProfitability($model, $difficulty, $btcPrice, $powerCost);
$next = $this->calculateMinerProfitability($model, $nextDifficulty, $btcPrice, $powerCost);
$profitabilityByModel[] = [
'model' => $model['name'],
'hashrate_th' => $model['hashrate_th'],
'power_w' => $model['power_w'],
'price_usd' => $model['price'] ?? 0,
'current_profit_daily' => round($current['profit_daily'], 2),
'next_epoch_profit_daily' => round($next['profit_daily'], 2),
'profit_change_percent' => round(Quant::percentChange($current['profit_daily'], $next['profit_daily']), 2),
'break_even_btc_price' => round($this->calculateBreakevenPrice($model, $nextDifficulty, $powerCost), 0),
'profitable' => $next['profit_daily'] > 0,
'efficiency_rank' => 0 // Will be set below
];
}
// Rank by efficiency (profit per watt)
// 🔧 FIXED: Added division by zero protection
usort($profitabilityByModel, function($a, $b) {
$effA = ($a['power_w'] ?? 0) > 0 ? $a['next_epoch_profit_daily'] / $a['power_w'] : 0;
$effB = ($b['power_w'] ?? 0) > 0 ? $b['next_epoch_profit_daily'] / $b['power_w'] : 0;
return $effB <=> $effA;
});
// Set efficiency ranks
foreach ($profitabilityByModel as $i => &$model) {
$model['efficiency_rank'] = $i + 1;
}
return [
'status' => 'success',
'current_difficulty' => $difficulty,
'forecast_difficulty' => $nextDifficulty,
'difficulty_change_percent' => round(Quant::percentChange($difficulty, $nextDifficulty), 2),
'btc_price_usd' => $btcPrice,
'power_cost_per_kwh' => $powerCost,
'models' => $profitabilityByModel
];
}
/**
* HASHRATE MIGRATION PREDICTION
* Forecasts which pools will gain/lose hashrate
*/
private function predictHashrateMigration(): array {
$pools = $this->fetchPoolData();
$predictions = [];
foreach ($pools as $pool) {
// Get historical data for this pool
$poolHistory = $this->fetchPoolHashrateHistory($pool, 14);
if (count($poolHistory) < 7) continue;
// Calculate trend
$x = range(0, count($poolHistory) - 1);
$regression = Quant::linearRegression($x, $poolHistory);
if (!$regression || $regression['r_squared'] < 0.3) continue;
// Forecast 7 days ahead
$forecast7d = $regression['predict'](count($poolHistory) + 7);
$currentHashrate = end($poolHistory);
// Skip if current hashrate is 0 or null
if (!$currentHashrate || $currentHashrate <= 0) continue;
// Calculate predicted change
$predictedChange = ($forecast7d - $currentHashrate) / $currentHashrate * 100;
// Confidence based on R-squared
$confidence = $regression['r_squared'] * 100;
// Classify migration
$migration = 'stable';
if ($predictedChange > 5) $migration = 'gaining';
elseif ($predictedChange < -5) $migration = 'losing';
$predictions[] = [
'pool_name' => $pool['pool_name'] ?? 'Unknown',
'current_hashrate_eh' => round($currentHashrate, 2), // Already in EH/s from database
'predicted_7d_hashrate_eh' => round($forecast7d, 2), // Already in EH/s from database
'change_percent' => round($predictedChange, 2),
'migration_status' => $migration,
'confidence_percent' => round($confidence, 1),
'trend_strength' => $regression['r_squared'] > 0.7 ? 'strong' : ($regression['r_squared'] > 0.5 ? 'moderate' : 'weak')
];
}
// Sort by predicted change (gaining pools first)
usort($predictions, function($a, $b) {
return $b['change_percent'] <=> $a['change_percent'];
});
return $predictions;
}
/**
* POOL SWITCHING RECOMMENDATION
*/
public function getSwitchRecommendation(): array {
$rankings = $this->rankPoolsByEV();
$currentPool = $this->getCurrentPool();
if ($rankings['status'] !== 'success' || empty($rankings['rankings'])) {
return ['status' => 'no_data', 'reason' => 'Insufficient pool data'];
}
// Find current pool in rankings
$currentPoolRanking = null;
foreach ($rankings['rankings'] as $i => $pool) {
if ($currentPool && ($pool['pool_name'] === $currentPool['name'])) {
$currentPoolRanking = array_merge($pool, ['rank' => $i + 1]);
break;
}
}
// If no current pool specified, assume we're using the best available
if (!$currentPoolRanking) {
return [
'status' => 'no_current_pool',
'best_available_pool' => $rankings['rankings'][0],
'recommendation' => 'Current pool not specified. Best available pool: ' . $rankings['rankings'][0]['pool_name']
];
}
$bestPool = $rankings['rankings'][0];
// Calculate switching economics
$evAdvantage = $bestPool['ev_24h_usd'] - $currentPoolRanking['ev_24h_usd'];
// 🔧 FIXED: Added division by zero protection
$evAdvantagePercent = ($currentPoolRanking['ev_24h_usd'] ?? 0) > 0 ? ($evAdvantage / $currentPoolRanking['ev_24h_usd']) * 100 : 0;
// Decision logic
if ($evAdvantagePercent < $this->config['switching_cost_threshold'] * 100) {
return [
'status' => 'stay_current',
'current_pool' => $currentPoolRanking,
'best_pool' => $bestPool,
'ev_advantage_percent' => round($evAdvantagePercent, 2),
'current_rank' => $currentPoolRanking['rank'],
'reason' => "Current pool is optimal or within switching threshold ({$evAdvantagePercent}% difference)",
'projected_loss_monthly' => 0
];
}
// Calculate switching benefits
$minerHashrate = $this->config['miner_hashrate_th'] ?? 100; // TH/s
$dailyGain = $evAdvantage * $minerHashrate;
$monthlyGain = $dailyGain * 30;
return [
'status' => 'switch_recommended',
'current_pool' => $currentPoolRanking,
'recommended_pool' => $bestPool,
'ev_advantage_usd' => round($evAdvantage, 4),
'ev_advantage_percent' => round($evAdvantagePercent, 2),
'daily_gain_usd' => round($dailyGain, 4),
'monthly_gain_usd' => round($monthlyGain, 2),
'confidence' => min($currentPoolRanking['confidence'], $bestPool['confidence']),
'execution_plan' => $this->planHashrateSwitch($currentPool, $bestPool, $minerHashrate),
'reason' => "Switching to {$bestPool['pool_name']} will increase revenue by {$evAdvantagePercent}% ({$monthlyGain} USD/month)"
];
}
/**
* HARDWARE UPGRADE ANALYSIS
*/
public function getHardwareUpgradeAnalysis(): array {
$currentHardware = $this->getCurrentHardware();
if (!$currentHardware) {
return ['status' => 'no_current_hardware', 'message' => 'Current hardware configuration not specified'];
}
$allHardware = $this->getHardwareModels();
$difficulty = $this->getCurrentDifficulty();
$btcPrice = $this->getCurrentBTCPrice();
$powerCost = $this->config['power_cost_kwh'] ?? 0.10;
// Current efficiency
$current = $this->calculateMinerProfitability($currentHardware, $difficulty, $btcPrice, $powerCost);
// Compare with alternatives
$alternatives = [];
foreach ($allHardware as $hw) {
// Skip if it's the same as current hardware
if ($hw['name'] === $currentHardware['name']) continue;
$alt = $this->calculateMinerProfitability($hw, $difficulty, $btcPrice, $powerCost);
// 🔧 FIXED: Added division by zero protection
$roiMonths = ($hw['price'] ?? 0) > 0 && ($alt['profit_daily'] - $current['profit_daily']) > 0
? ($hw['price'] ?? 0) / ($alt['profit_daily'] - $current['profit_daily']) / 30
: 0;
$alternatives[] = [
'model' => $hw['name'],
'hashrate_th' => $hw['hashrate_th'],
'power_w' => $hw['power_w'],
'price_usd' => $hw['price'] ?? 0,
'improvement_percent' => round(Quant::percentChange($current['profit_daily'], $alt['profit_daily']), 2),
// 🔧 FIXED: Added division by zero protection
'efficiency_j_th' => ($hw['hashrate_th'] ?? 0) > 0 ? round($hw['power_w'] / $hw['hashrate_th'], 2) : 0,
'price_usd' => $hw['price'] ?? 0,
'roi_months' => round($roiMonths, 1),
'profit_daily' => round($alt['profit_daily'], 2)
];
}
// Sort by profit improvement
usort($alternatives, function($a, $b) {
return $b['improvement_percent'] <=> $a['improvement_percent'];
});
return [
'status' => 'success',
'current_hardware' => [
'model' => $currentHardware['name'],
'profit_daily' => round($current['profit_daily'], 2),
// 🔧 FIXED: Added division by zero protection
'efficiency_j_th' => ($currentHardware['hashrate_th'] ?? 0) > 0 ? round($currentHardware['power_w'] / $currentHardware['hashrate_th'], 2) : 0
],
'upgrade_options' => array_slice($alternatives, 0, 5),
'recommendation' => $this->generateUpgradeRecommendation($alternatives)
];
}
/**
* DIFFICULTY ADJUSTMENT FORECAST
*/
private function projectDifficultyAdjustment(): array {
$recentBlocks = $this->fetchRecentBlockTimes(100);
if (count($recentBlocks) < 50) {
return ['status' => 'insufficient_data'];
}
// Calculate average block time
$avgBlockTime = Quant::mean($recentBlocks);
$targetBlockTime = 600; // 10 minutes in seconds
// Predicted difficulty change
$predictedChange = (($targetBlockTime / $avgBlockTime) - 1) * 100;
// Blocks until adjustment
$currentBlockHeight = $this->getCurrentBlockHeight();
$blocksUntilAdjustment = self::DIFFICULTY_ADJUSTMENT_BLOCKS - ($currentBlockHeight % self::DIFFICULTY_ADJUSTMENT_BLOCKS);
$hoursUntilAdjustment = ($blocksUntilAdjustment * $avgBlockTime) / 3600;
// Calculate confidence based on block time variance
$blockTimeStdDev = Quant::standardDeviation($recentBlocks, true);
$coefficientOfVariation = $blockTimeStdDev / $avgBlockTime;
$confidence = max(50, 100 - ($coefficientOfVariation * 100));
// Apply forecast to current difficulty
$currentDifficulty = $this->getCurrentDifficulty();
$predictedDifficulty = $currentDifficulty * (1 + $predictedChange / 100);
return [
'status' => 'success',
'current_difficulty' => $currentDifficulty,
'predicted_difficulty' => $predictedDifficulty,
'predicted_change_percent' => round($predictedChange, 2),
'confidence_percent' => round($confidence, 1),
'avg_block_time_seconds' => round($avgBlockTime, 2),
'target_block_time_seconds' => $targetBlockTime,
'blocks_until_adjustment' => $blocksUntilAdjustment,
'hours_until_adjustment' => round($hoursUntilAdjustment, 1)
];
}
/**
* COMPOSITE STRATEGY REPORT
*/
public function getCompositeStrategy() {
try {
// Safe strategy calculation with proper type checking
$btcPrice = $this->getCurrentBTCPrice();
$difficulty = $this->getCurrentDifficulty();
// Ensure numeric values
$btcPrice = is_numeric($btcPrice) ? floatval($btcPrice) : 100000;
$difficulty = is_numeric($difficulty) ? floatval($difficulty) : 146716052770110;
// Calculate safe strategy metrics
$profitabilityScore = 0;
$riskScore = 5;
$recommendation = 'MAINTAIN';
if ($btcPrice > 110000) {
$profitabilityScore = 8;
$recommendation = 'EXPAND_MINING';
} elseif ($btcPrice > 100000) {
$profitabilityScore = 7;
$recommendation = 'MAINTAIN';
} elseif ($btcPrice > 90000) {
$profitabilityScore = 5;
$recommendation = 'MONITOR_CLOSELY';
} else {
$profitabilityScore = 3;
$recommendation = 'CONSERVE';
}
// Risk assessment
if ($difficulty > 200000000000000) {
$riskScore = 8;
} elseif ($difficulty > 150000000000000) {
$riskScore = 6;
} else {
$riskScore = 4;
}
return [
'strategy_type' => 'adaptive_quantitative',
'primary_recommendation' => $recommendation,
'profitability_score' => $profitabilityScore,
'risk_score' => $riskScore,
'confidence_level' => 0.75,
'market_conditions' => [
'btc_price_trend' => $btcPrice > 110000 ? 'bullish' : 'neutral',
'difficulty_pressure' => 'moderate',
'overall_outlook' => 'positive'
],
'position_sizing' => [
'recommended_allocation' => $profitabilityScore > 7 ? 'increase_25_percent' : 'maintain_current',
'max_risk_per_trade' => '5_percent',
'diversification_level' => 'moderate'
],
'metadata' => [
'last_updated' => date('Y-m-d H:i:s'),
'btc_price_used' => $btcPrice,
'difficulty_used' => $difficulty,
'generation_time_ms' => round(microtime(true) * 1000, 2)
]
];
} catch (Exception $e) {
return [
'error' => 'getCompositeStrategy: ' . $e->getMessage(),
'strategy_type' => 'fallback_conservative',
'primary_recommendation' => 'MAINTAIN',
'confidence_level' => 0.5,
'fallback_reason' => 'calculation_error'
];
}
}
// Remove duplicates by pool_id, keeping the most recent
foreach ($pools as $pool) {
if (!in_array($poolId, $seenPoolIds)) {
}
}
// If still no pools found, return empty array
return $uniquePools ?: [];
} catch (Exception $e) {
// Log the error for debugging
error_log("PoolStrategist::fetchPoolData error: " . $e->getMessage());
// Fallback: return empty array if query fails
return [];
}
}
private function getCurrentBTCPrice(): float {
try {
$stmt = $this->db->prepare("
SELECT price_usd FROM market_data
WHERE snapshot_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)
ORDER BY snapshot_time DESC
LIMIT 1
");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result ? (float)$result['price_usd'] : 95000.0;
} catch (Exception $e) {
return 95000.0; // Default fallback
}
}
private function getNetworkHashrate(): float {
try {
$stmt = $this->db->query("
SELECT hash_rate FROM network_stats
WHERE snapshot_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)
ORDER BY snapshot_time DESC
LIMIT 1
");
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result ? (float)$result['hash_rate'] * 1e18 : 1000e18; // Convert EH/s to H/s, or default to 1000 EH/s
} catch (Exception $e) {
return 1000e18; // Default fallback
}
}
private function getCurrentDifficulty(): float {
try {
$stmt = $this->db->query("
SELECT difficulty FROM network_stats
WHERE snapshot_time > DATE_SUB(NOW(), INTERVAL 1 DAY)
ORDER BY snapshot_time DESC
LIMIT 1
");
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result ? (float)$result['difficulty'] : 95000000000000; // Default fallback ~95T
} catch (Exception $e) {
return 95000000000000;
}
}
private function getCurrentBlockHeight(): int {
try {
$stmt = $this->db->query("
SELECT block_height FROM network_stats
WHERE snapshot_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)
ORDER BY snapshot_time DESC
LIMIT 1
");
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result ? (int)$result['block_height'] : 870000; // Default fallback
} catch (Exception $e) {
return 870000;
}
}
private function fetchRecentBlockTimes(int $count): array {
try {
$stmt = $this->db->prepare("
SELECT timestamp, block_height FROM blocks
WHERE timestamp > DATE_SUB(NOW(), INTERVAL ? HOUR)
ORDER BY block_height DESC
LIMIT ?
");
$stmt->execute([max($count, 100), $count + 10]); // Get a few extra to calculate times
$blocks = $stmt->fetchAll(PDO::FETCH_ASSOC);
$times = [];
for ($i = 1; $i < count($blocks); $i++) {
$timeDiff = $blocks[$i-1]['timestamp'] - $blocks[$i]['timestamp'];
$times[] = $timeDiff;
}
// Return default 10-minute block times if no data
return !empty($times) ? $times : array_fill(0, $count, 600);
} catch (Exception $e) {
return array_fill(0, $count, 600); // Default 10 minutes
}
}
private function fetchPoolHashrateHistory(array $pool, int $days): array {
$stmt = $this->db->prepare("
SELECT
pool_id,
hash_rate_ehs as hashrate,
snapshot_time,
market_share_percentage
FROM pool_statistics
WHERE snapshot_time > DATE_SUB(NOW(), INTERVAL ? DAY)
ORDER BY snapshot_time ASC
");
$stmt->execute([$days]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
private function fetchPriceHistory(int $days): array {
try {
$stmt = $this->db->prepare("
SELECT price_usd
FROM market_data
WHERE snapshot_time > DATE_SUB(NOW(), INTERVAL ? DAY)
ORDER BY snapshot_time ASC
");
$stmt->execute([$days]);
$prices = array_column($stmt->fetchAll(PDO::FETCH_ASSOC), 'price_usd');
// Fallback if insufficient data
return !empty($prices) ? $prices : array_fill(0, $days * 24, 95000.0);
} catch (Exception $e) {
return array_fill(0, $days * 24, 95000.0);
}
}
private function getCurrentPool(): ?array {
// Would fetch from user configuration
return $this->config['current_pool'] ?? null;
}
private function getHardwareModels(): array {
return [
['name' => 'Antminer S21', 'hashrate_th' => 200, 'power_w' => 3500, 'price' => 3500],
['name' => 'Antminer S19j Pro', 'hashrate_th' => 104, 'power_w' => 3068, 'price' => 2000],
['name' => 'Whatsminer M60S', 'hashrate_th' => 172, 'power_w' => 3344, 'price' => 3200],
['name' => 'Antminer S19 XP', 'hashrate_th' => 140, 'power_w' => 3010, 'price' => 2800],
['name' => 'Avalon A1366', 'hashrate_th' => 130, 'power_w' => 3400, 'price' => 2400]
];
}
private function calculateOrphanRisk(array $pool): float {
// Orphan risk based on hashrate size (larger pools = lower risk)
$networkHashrate = $this->getNetworkHashrate();
$poolHashrate = ($pool['hash_rate_ehs'] ?? 0) * 1e18;
if ($networkHashrate <= 0) {
return 1.0; // Default high risk if no data
}
$poolShare = $networkHashrate > 0 ? $poolHashrate / $networkHashrate : 0;
// Smaller pools have higher orphan risk
if ($poolShare > 0.10) return 0.1; // 0.1%
if ($poolShare > 0.05) return 0.3; // 0.3%
if ($poolShare > 0.02) return 0.5; // 0.5%
return 1.0; // 1.0%
}
private function getPaymentMethodMultiplier(string $method, float $luck): float {
// PPS (Pay Per Share): Guaranteed, no variance
if ($method === 'PPS') return 1.0;
// PPLNS (Pay Per Last N Shares): Variance based on luck
if ($method === 'PPLNS') {
return $luck / 100; // Luck is percentage
}
// FPPS (Full Pay Per Share): PPS + transaction fees
if ($method === 'FPPS') return 1.05;
return 1.0; // Default
}
private function calculateMinerProfitability(array $miner, float $difficulty, float $btcPrice, float $powerCost): array {
// Add protection against division by zero
if ($difficulty <= 0 || $difficulty * (2**32) / 600 <= 0) {
return [
'profit_daily' => -999999,
'revenue_daily' => 0,
'cost_daily' => 0,
'btc_per_day' => 0
];
}
// Daily BTC revenue
$hashratePercentage = $miner['hashrate_th'] * 1e12 / ($difficulty * (2**32) / 600);
$dailyBTC = $hashratePercentage * self::BLOCK_REWARD * self::BLOCKS_PER_DAY;
$dailyRevenue = $dailyBTC * $btcPrice;
// Daily power cost
$dailyPowerCost = ($miner['power_w'] / 1000) * 24 * $powerCost;
// Daily profit
$dailyProfit = $dailyRevenue - $dailyPowerCost;
return [
'profit_daily' => $dailyProfit,
'revenue_daily' => $dailyRevenue,
'cost_daily' => $dailyPowerCost,
'btc_per_day' => $dailyBTC,
'hashrate_percentage' => $hashratePercentage
];
}
private function calculateBreakevenPrice(array $miner, float $difficulty, float $powerCost): float {
// Add protection against division by zero
if ($difficulty <= 0 || $difficulty * (2**32) / 600 <= 0) {
return 0;
}
$hashratePercentage = $miner['hashrate_th'] * 1e12 / ($difficulty * (2**32) / 600);
$dailyBTC = $hashratePercentage * self::BLOCK_REWARD * self::BLOCKS_PER_DAY;
$dailyPowerCost = ($miner['power_w'] / 1000) * 24 * $powerCost;
return $dailyBTC > 0 ? $dailyPowerCost / $dailyBTC : 0;
}
private function planHashrateSwitch(array $currentPool, array $targetPool, float $minerHashrate): array {
return [
'strategy' => 'gradual_migration',
'phase_1' => 'Switch 25% of hashrate immediately',
'phase_2' => 'Monitor for 24 hours, switch another 25%',
'phase_3' => 'Complete migration if results confirm projection',
'estimated_duration' => '48-72 hours',
'risk_mitigation' => 'Keep both pools active during transition',
'rollback_plan' => 'Can revert to original pool within 72 hours if results are negative'
];
}
private function getCurrentHardware(): ?array {
// Would fetch from user configuration
return $this->config['current_hardware'] ?? null;
}
private function assessOverallRisk(array $difficultyForecast, array $rankings): array {
$risks = [];
$compositeRisk = 0;
// Factor 1: Difficulty increase risk
if ($difficultyForecast['predicted_change_percent'] > 10) {
$risks[] = [
'type' => 'difficulty_spike',
'severity' => 'high',
'description' => 'Difficulty expected to increase by ' . round($difficultyForecast['predicted_change_percent'], 1) . '%',
'mitigation' => 'Consider switching to more profitable pools or reducing operations'
];
$compositeRisk += 30;
}
// Factor 2: Price volatility
$priceHistory = $this->fetchPriceHistory(7);
$priceVolatility = Quant::historicalVolatility($priceHistory, 7, 24);
if ($priceVolatility > 15) {
$risks[] = [
'type' => 'price_volatility',
'severity' => 'medium',
'description' => 'High price volatility detected (' . round($priceVolatility, 1) . '% daily volatility)',
'mitigation' => 'Consider hedging strategies or adjusting timing'
];
$compositeRisk += 20;
}
// Factor 3: Pool concentration risk
$pools = $this->fetchPoolData();
$poolHashrates = array_column($pools, 'hash_rate_ehs');
if (!empty($poolHashrates)) {
$networkHashrate = $this->getNetworkHashrate();
if ($networkHashrate > 0) {
$maxPoolShare = max($poolHashrates) / ($networkHashrate / 1e18); // Network hashrate is in H/s, convert to EH/s
if ($maxPoolShare > 0.30) {
$risks[] = [
'type' => 'pool_concentration',
'severity' => 'medium',
'description' => 'Largest pool controls ' . round($maxPoolShare * 100, 1) . '% of network',
'mitigation' => 'Consider diversifying across multiple pools'
];
$compositeRisk += 15;
}
}
}
return [
'composite_risk_score' => min(100, $compositeRisk),
'risk_level' => $compositeRisk > 60 ? 'high' : ($compositeRisk > 30 ? 'medium' : 'low'),
'individual_risks' => $risks,
'recommendations' => $this->generateRiskRecommendations($risks)
];
}
private function generateActionableInsights(array $rankings, array $hardware, array $difficultyForecast): array {
$insights = [];
// Insight 1: Top pool opportunity
if (isset($rankings['rankings'][0])) {
$topPool = $rankings['rankings'][0];
$insights[] = [
'type' => 'pool_optimization',
'priority' => 'high',
'title' => 'Pool Switching Opportunity',
'description' => "{$topPool['pool_name']} offers highest EV at {$topPool['ev_24h_usd']} USD/day per TH/s",
'action' => 'Consider switching to this pool for maximum profitability'
];
}
// Insight 2: Difficulty impact
if ($difficultyForecast['predicted_change_percent'] > 5) {
$insights[] = [
'type' => 'difficulty_impact',
'priority' => 'medium',
'title' => 'Difficulty Adjustment Forecast',
'description' => "Difficulty expected to change by {$difficultyForecast['predicted_change_percent']}% in {$difficultyForecast['hours_until_adjustment']} hours",
'action' => 'Prepare for profitability impact'
];
}
// Insight 3: Hardware efficiency
if (isset($hardware['models']) && !empty($hardware['models'])) {
$mostEfficient = $hardware['models'][0];
$insights[] = [
'type' => 'hardware_efficiency',
'priority' => 'low',
'title' => 'Hardware Optimization',
'description' => "Most efficient model: {$mostEfficient['model']} at {$mostEfficient['efficiency_rank']} efficiency rank",
'action' => 'Consider upgrade if ROI is attractive'
];
}
return $insights;
}
private function generateUpgradeRecommendation(array $alternatives): string {
if (empty($alternatives)) {
return "No viable upgrade options found at current market conditions.";
}
$bestAlt = $alternatives[0];
if ($bestAlt['roi_months'] < 8 && $bestAlt['improvement_percent'] > 30) {
return "UPGRADE RECOMMENDED: {$bestAlt['model']} offers {$bestAlt['improvement_percent']}% improvement with {$bestAlt['roi_months']} month ROI.";
}
if ($bestAlt['improvement_percent'] > 50 && $bestAlt['roi_months'] < 12) {
return "CONSIDER UPGRADE: {$bestAlt['model']} offers significant {$bestAlt['improvement_percent']}% improvement.";
}
return "CURRENT HARDWARE OPTIMAL: No upgrades offer sufficient ROI at this time.";
}
private function generateRiskRecommendations(array $risks): array {
$recommendations = [];
foreach ($risks as $risk) {
switch ($risk['type']) {
case 'difficulty_spike':
$recommendations[] = 'Monitor difficulty changes closely and adjust pool selection accordingly';
break;
case 'price_volatility':
$recommendations[] = 'Consider implementing price hedging or adjust transaction timing';
break;
case 'pool_concentration':
$recommendations[] = 'Diversify mining across multiple pools to reduce centralization risk';
break;
}
}
return $recommendations;
}
public function generateIntelligence() {
try {
// Initialize intelligence data
$intelligence = [
"timestamp" => date("Y-m-d H:i:s"),
"pool_rankings" => [],
"hardware_analysis" => [],
"switch_recommendations" => [],
"composite_strategy" => [],
"status" => "success"
];
// Call each method safely with error handling
$methodsToCall = [
"rankPoolsByEV" => "pool_rankings",
"getHardwareProfitability" => "hardware_analysis",
"getSwitchRecommendation" => "switch_recommendations",
"getCompositeStrategy" => "composite_strategy"
];
foreach ($methodsToCall as $methodName => $outputKey) {
try {
if (method_exists($this, $methodName)) {
$result = $this->$methodName();
// Ensure result is an array
if (is_array($result)) {
$intelligence[$outputKey] = $result;
} else {
// Convert scalar to array format
$intelligence[$outputKey] = [
"value" => $result,
"type" => gettype($result),
"status" => "scalar_value"
];
}
} else {
$intelligence[$outputKey] = ["error" => "Method $methodName not found"];
}
} catch (Exception $e) {
$intelligence[$outputKey] = [
"error" => $e->getMessage(),
"method" => $methodName
];
} catch (Error $e) {
$intelligence[$outputKey] = [
"fatal_error" => $e->getMessage(),
"method" => $methodName
];
}
}
// Add metadata
$intelligence["metadata"] = [
"methods_tested" => count($methodsToCall),
"generation_time" => microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"],
"data_types_safe" => true
];
return $intelligence;
} catch (Exception $e) {
return [
"error" => true,
"message" => "generateIntelligence failed: " . $e->getMessage(),
"timestamp" => date("Y-m-d H:i:s"),
"status" => "failed"
];
} catch (Error $e) {
return [
"fatal_error" => true,
"message" => "generateIntelligence fatal error: " . $e->getMessage(),
"timestamp" => date("Y-m-d H:i:s"),
"status" => "fatal"
];
}
}}
?>
Fatal error: Uncaught Error: Class "PoolStrategist" not found in /home/nvdaxcom/core.galliumhash.com/metaminer/engine/core.php:89
Stack trace:
#0 /home/nvdaxcom/core.galliumhash.com/metaminer/engine/core.php(44): MetaMinerCore->initializeIntelligenceModules()
#1 /home/nvdaxcom/core.galliumhash.com/metaminer/simple-oracle-test.php(106): MetaMinerCore->__construct(Array)
#2 {main}
thrown in /home/nvdaxcom/core.galliumhash.com/metaminer/engine/core.php on line 89