<?php
//die();
date_default_timezone_set("Asia/Tehran");
error_reporting(E_ALL);
ini_set('display_errors', '1');
set_time_limit(55);

$path1 = 'data/CoinexOHLC';
$Coinexfiles = scandir($path1);
$StochResults = [];
$StochResults['time'] = date('Y-m-d H:i:s');
foreach ($Coinexfiles as $file) {
    if ($file == '.' || $file == '..')
        continue;
    $symbol = str_replace('.json', '', $file);
    $data = readJson($path1 . '/' . $file);
    if (!isset($data->data) || $data->message !== "OK") {
//        file_put_contents('logBestCoinex.txt', json_encode([date('Y-m-d H:i:s'), $symbol . ' OHLC']) . PHP_EOL, FILE_APPEND);
        continue;
    }
    // تبدیل داده‌ها به فرمت مناسب
    $candles = [];
    $dataArray = $data->data;

    foreach ($dataArray as $index)
        $candles[] = [
            'open' => (float)$index->open,
            'high' => (float)$index->high,
            'low' => (float)$index->low,
            'close' => (float)$index->close,
            'volume' => isset($index->volume) ? (float)$index->volume : 0
        ];

    if ($candles) {
        list($bestLength, $bestKSmoothing, $bestDSmoothing, $bestOversold, $bestOverbought, $maxProfit) = optimizeStochastic($candles, [20, 50], [1, 1], [1, 1], [10, 40], [60, 85]); //[65, 85])

        $closes = array_column($candles, 'close');

        unset($closes[count($closes) - 1]);
        $rsi = calculateRSI($closes);
        list($RSIupper, $RSIlower) = findRSIPeaks($rsi);

        $StochResults[$symbol] = [
            'Stochlength' => $bestLength,
            'StochK' => $bestKSmoothing,
            'StochD' => $bestDSmoothing,
            'StochLower' => $bestOversold,
            'StochUpper' => $bestOverbought,
            'StochProfit' => $maxProfit,

            'RSIlength' => 14,
            'RSIupper' => ($RSIupper ?? 70) - 2,
            'RSIlower' => ($RSIlower && $RSIlower < 50 ? $RSIlower : 30) //+ 5
        ];

    }
}

file_put_contents('data/BestCoinexStoch.json', json_encode($StochResults, JSON_PRETTY_PRINT));

function calculateStochastic($candles, $length, $kSmoothing = 3, $dSmoothing = 3)
{

    $stochK = [];
    $stochD = [];

    for ($i = $length - 1; $i < count($candles); $i++) {
        $highs = array_column(array_slice($candles, $i - $length + 1, $length), 'high');
        $lows = array_column(array_slice($candles, $i - $length + 1, $length), 'low');

        $highestHigh = max($highs);
        $lowestLow = min($lows);

        $close = $candles[$i]['close'];
        $k = ($highestHigh - $lowestLow == 0) ? 50 : (($close - $lowestLow) / ($highestHigh - $lowestLow)) * 100;
        $stochK[] = $k;
    }

    $smoothedK = [];
    for ($i = $kSmoothing - 1; $i < count($stochK); $i++) {
        $smoothedK[] = array_sum(array_slice($stochK, $i - $kSmoothing + 1, $kSmoothing)) / $kSmoothing;
    }

    for ($i = $dSmoothing - 1; $i < count($smoothedK); $i++) {
        $stochD[] = array_sum(array_slice($smoothedK, $i - $dSmoothing + 1, $dSmoothing)) / $dSmoothing;
    }

    return ["stochK" => $smoothedK, "stochD" => $stochD];
}

function simulateStochasticTrading($candles, $stochK, $stochD, $oversold, $overbought)
{

    $position = false; // آیا موقعیت باز است یا خیر
    $entryPrice = 0; // قیمت ورود به معامله
    $profit = 0; // سود کلی
    $feeRate = 0.0005; // نرخ کارمزد (0.1 درصد)


    for ($i = 0; $i < count($stochK) - 4; $i++) {
        if ($stochK[$i] < $oversold && $stochD[$i] < $oversold && !$position) {
            $entryPrice = $candles[$i]['close'];
            $position = true;
        } elseif ($stochK[$i] > $overbought && $stochD[$i] > $overbought && $position) {
//            $profit += ($candles[$i]['close'] - $position)* (1 - $feeRate);
//            $position = null;
            $exitPrice = $candles[$i]['close'];

            // محاسبه سود با احتساب کارمزد
            $grossProfit = $exitPrice - $entryPrice; // سود خام
            $fee = ($entryPrice + $exitPrice) * $feeRate; // جمع کارمزد
            $netProfit = $grossProfit - $fee;

            $profit += $netProfit; // اضافه کردن سود خالص
            $position = false; // موقعیت بسته شد
        }
    }
    if ($position) {
        $profit -= $entryPrice * $feeRate; // کسر کارمزد ورود
    }

    return $profit;
}

function optimizeStochastic($candles, $lengthRange, $kSmoothingRange, $dSmoothingRange, $oversoldRange, $overboughtRange)
{
    $bestLength = $lengthRange[0];
    $bestKSmoothing = $kSmoothingRange[0];
    $bestDSmoothing = $dSmoothingRange[0];
    $bestOversold = $oversoldRange[0];
    $bestOverbought = $overboughtRange[0];
    $maxProfit = 0;

    for ($length = $lengthRange[0]; $length <= $lengthRange[1]; $length += 2) {
        for ($kSmoothing = $kSmoothingRange[0]; $kSmoothing <= $kSmoothingRange[1]; $kSmoothing += 2) {
            for ($dSmoothing = $dSmoothingRange[0]; $dSmoothing <= $dSmoothingRange[1]; $dSmoothing++) {
                $stoch = calculateStochastic($candles, $length, $kSmoothing, $dSmoothing);

                for ($oversold = $oversoldRange[0]; $oversold <= $oversoldRange[1]; $oversold += 2) {
                    for ($overbought = $overboughtRange[0]; $overbought <= $overboughtRange[1]; $overbought += 2) {
                        if ($oversold >= $overbought) {
                            continue;
                        }
                        if (count($candles) < $length) {
//                            error_log("داده‌های ورودی برای محاسبه استوکاستیک کافی نیست.");
                            continue;
                        }
                        $profit = simulateStochasticTrading($candles, $stoch["stochK"], $stoch["stochD"], $oversold, $overbought);

                        if ($profit > $maxProfit) {
                            $maxProfit = $profit;
                            $bestLength = $length;
                            $bestKSmoothing = $kSmoothing;
                            $bestDSmoothing = $dSmoothing;
                            $bestOversold = $oversold;
                            $bestOverbought = $overbought;
                        }
                    }
                }
            }
        }
    }

    return [$bestLength, $bestKSmoothing, $bestDSmoothing, $bestOversold, $bestOverbought, $maxProfit];
}

function calculateRSI($data, $length = 14)
{
    if (count($data) < $length + 1) {
        return [];
    }

    $gains = $losses = [];
    for ($i = $length + 2; $i < count($data); $i++) {
        $change = $data[$i] - $data[$i - 1];
        $gains[] = $change > 0 ? $change : 0;
        $losses[] = $change < 0 ? abs($change) : 0;
    }

    $avgGain = array_sum(array_slice($gains, 0, $length)) / $length;
    $avgLoss = array_sum(array_slice($losses, 0, $length)) / $length;

    $rsi = [];
    for ($i = $length; $i < count($gains); $i++) {
        $avgGain = (($avgGain * ($length - 1)) + $gains[$i]) / $length;
        $avgLoss = (($avgLoss * ($length - 1)) + $losses[$i]) / $length;
        $avgGain = max($avgGain, 0.0001); // جلوگیری از صفر شدن avgGain
        $avgLoss = max($avgLoss, 0.0001); // جلوگیری از صفر شدن avgLoss
        $rs = $avgLoss == 0 ? 100 : $avgGain / $avgLoss;
        $rsi[] = round((100 - (100 / (1 + $rs))), 2);
    }

    return $rsi;
}

//function findRSIPeaks($rsi, $minDistance = 15, $maxDeviation = 5)
//{
//    // حذف مقادیر تکراری و مرتب‌سازی آرایه
//    $unique_sorted = array_values(array_unique($rsi));
////    sort($unique_sorted);
//    if (!empty($unique_sorted)) {
//        $min = min($unique_sorted);
//        $max = max($unique_sorted);
//        $minList = $maxList = [];
//        foreach ($unique_sorted as $value) {
//            if ($max - $value < $maxDeviation)
//                $maxList[] = $value;
//            if ($value - $min < $maxDeviation)
//                $minList[] = $value;
//        }
//
//        $up = array_sum($maxList) / count($maxList);
//        $down = array_sum($minList) / count($minList);
//
//        return [$up, $down];
//    }
//    return [];
//}

function findRSIPeaks($rsi, $lookback = 180, $tolerance = 4, $minTouches = 2)
{
    $supportLevels = [];
//    $rsi = array_slice($rsi, -$lookback);

    for ($i = 1; $i < count($rsi) - 1; $i++) {
        if ($rsi[$i] < $rsi[$i - 1] && $rsi[$i] < $rsi[$i + 1]) {
            $supportLevels[] = $rsi[$i];
        }
    }

    if (empty($supportLevels)) {
        if (empty($rsi)) {
            return [70, 30]; 
        }

        $minRsi = min($rsi);
        return [70, $minRsi + $tolerance];
    }


    // گروه‌بندی سطوح حمایت مشابه
    $grouped = [];
    foreach ($supportLevels as $level) {
        $found = false;
        foreach ($grouped as &$group) {
            if (abs($group['level'] - $level) <= $tolerance) {
                $group['count']++;
                $group['values'][] = $level;
                $found = true;
                break;
            }
        }
        if (!$found) {
            $grouped[] = ['level' => $level, 'count' => 1, 'values' => [$level]];
        }
    }

    // اولویت با کم‌ترین سطح RSI که شرط برخورد رو داره
    usort($grouped, function ($a, $b) {
        return $a['level'] <=> $b['level'];
    });

    foreach ($grouped as $g) {
        if ($g['count'] >= $minTouches) {
            $strongSupport = round(array_sum($g['values']) / count($g['values']), 2);
            return [70, $strongSupport + $tolerance];
        }
    }

    // اگر هیچ سطح با minTouches پیدا نشد → کمترین مقدار RSI
    $minRsi = min($rsi);
    return [70, $minRsi + $tolerance];
}


function readJson($path) {
    if (!file_exists($path)) {
        usleep(300000);
        if (!file_exists($path)) {
            return [];
        }
    }
    $fileSize = filesize($path);
    if ($fileSize === 0) return [];

    $file = fopen($path, "r");
    if (!$file) return [];

    $response = fread($file, $fileSize);
    fclose($file);
    return json_decode($response) ?: [];
}
