CORE TERMINAL
DAILY -M72 : 일상

세상일도 작업도 모든 것이 언제나 손이 많이 간다.

DATE: 2026-03-03 09:55
분류 정보
핵심 항목
일상 반신욕
중요 데몬 작업 & 디비 정리
필수 청결 & 위생 블럭 정리 - 지퍼백
* 세상일도 작업도 모든 것이 언제나 손이 많이 간다.
1. 데몬 작업을 완성하고 나니 코드의 시작이 구조가 잘못됐다는 것이 또 손이 간다.
가. 속도 문제 개선
  ㄱ. 바이비트
  ㄴ. 업비트
ADDITIONAL SOURCE CODE
#!/usr/bin/php
<?php
/**
 * ============================================================
 * 바이비트 무기한 선물(linear) 종목 정보 수집 CLI 데몬
 * - curl_multi 병렬 호출 방식 (전체 종목 동시 호출)
 * - 그누보드(g5_write_daemon_kind_bybit) x2_run=1 종목만 수집
 * - 저장 테이블: daemon_bybit_Ticker
 * ============================================================
 */

error_reporting(E_ALL);
ini_set(\\\'display_errors\\\', 1);
date_default_timezone_set(\\\'Asia/Seoul\\\');

$DAEMON_ID = pathinfo(__FILE__, PATHINFO_FILENAME);

if (php_sapi_name() !== \\\'cli\\\') {
    echo \\\"CLI 전용 데몬입니다.\\\\n\\\";
    exit;
}

function get_db_connection() {
    try {
        $db_upbit = null;
        @include \\\'/home/www/DB/db_upbit.php\\\';
        if (!($db_upbit instanceof PDO)) return null;
        $pdo = $db_upbit;
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch (Throwable $e) {
        return null;
    }
}

function get_gnu_connection() {
    try {
        $db_gnu  = null;
        $pdo_gnu = null;
        $pdo     = null;
        @include \\\'/home/www/DB/db_gnu.php\\\';
        if ($db_gnu instanceof PDO) {
            $db_gnu->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $db_gnu;
        }
        if ($pdo_gnu instanceof PDO) {
            $pdo_gnu->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $pdo_gnu;
        }
        if ($pdo instanceof PDO) {
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $pdo;
        }
        return null;
    } catch (Throwable $e) {
        return null;
    }
}

// ============================================================
// curl_multi 병렬 호출 - URL 배열 한번에 날리고 결과 반환
// ============================================================
function http_multi_get(array $urls): array {
    $mh      = curl_multi_init();
    $handles = [];

    foreach ($urls as $key => $url) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 8,
            CURLOPT_USERAGENT      => \\\'bybit-ghost\\\',
            CURLOPT_SSL_VERIFYPEER => false,
        ]);
        curl_multi_add_handle($mh, $ch);
        $handles[$key] = $ch;
    }

    $running = null;
    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh);
    } while ($running > 0);

    $results = [];
    foreach ($handles as $key => $ch) {
        $raw = curl_multi_getcontent($ch);
        $results[$key] = $raw ? json_decode($raw, true) : null;
        curl_multi_remove_handle($mh, $ch);
        curl_close($ch);
    }
    curl_multi_close($mh);

    return $results;
}

// ============================================================
// 전체 종목 한번에 병렬 호출 후 데이터 파싱
// ============================================================
function collectAll(array $symbols): array {
    $API_INSTRUMENTS   = \\\'https://api.bybit.com/v5/market/instruments-info?category=linear&symbol=\\\';
    $API_TICKERS       = \\\'https://api.bybit.com/v5/market/tickers?category=linear&symbol=\\\';
    $API_KLINE         = \\\'https://api.bybit.com/v5/market/kline?category=linear&interval=1&limit=1&symbol=\\\';
    $API_RECENT_TRADE  = \\\'https://api.bybit.com/v5/market/recent-trade?category=linear&limit=1&symbol=\\\';
    $API_RISK_LIMIT    = \\\'https://api.bybit.com/v5/market/risk-limit?category=linear&symbol=\\\';
    $API_ACCOUNT_RATIO = \\\'https://api.bybit.com/v5/market/account-ratio?category=linear&period=1d&limit=1&symbol=\\\';
    $API_MARK_KLINE    = \\\'https://api.bybit.com/v5/market/mark-price-kline?category=linear&interval=1&limit=1&symbol=\\\';
    $API_INDEX_KLINE   = \\\'https://api.bybit.com/v5/market/index-price-kline?category=linear&interval=1&limit=1&symbol=\\\';
    $API_PREMIUM_KLINE = \\\'https://api.bybit.com/v5/market/premium-index-price-kline?category=linear&interval=1&limit=1&symbol=\\\';

    // 전체 종목 × 9개 URL 한번에 구성
    $urls = [];
    foreach ($symbols as $sym) {
        $s = urlencode($sym);
        $urls[\\\"{$sym}__info\\\"]    = $API_INSTRUMENTS   . $s;
        $urls[\\\"{$sym}__ticker\\\"]  = $API_TICKERS       . $s;
        $urls[\\\"{$sym}__kline\\\"]   = $API_KLINE         . $s;
        $urls[\\\"{$sym}__trade\\\"]   = $API_RECENT_TRADE  . $s;
        $urls[\\\"{$sym}__risk\\\"]    = $API_RISK_LIMIT    . $s;
        $urls[\\\"{$sym}__ratio\\\"]   = $API_ACCOUNT_RATIO . $s;
        $urls[\\\"{$sym}__mark\\\"]    = $API_MARK_KLINE    . $s;
        $urls[\\\"{$sym}__index\\\"]   = $API_INDEX_KLINE   . $s;
        $urls[\\\"{$sym}__premium\\\"] = $API_PREMIUM_KLINE . $s;
    }

    // 한방에 병렬 호출
    $raw = http_multi_get($urls);

    // 종목별 파싱
    $result = [];
    foreach ($symbols as $sym) {

        // instruments-info
        $res  = $raw[\\\"{$sym}__info\\\"] ?? null;
        $item = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? []) : [];
        $lf = $item[\\\'leverageFilter\\\'] ?? [];
        $pf = $item[\\\'priceFilter\\\']    ?? [];
        $ls = $item[\\\'lotSizeFilter\\\']  ?? [];

        // tickers
        $res = $raw[\\\"{$sym}__ticker\\\"] ?? null;
        $tk  = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? null) : null;

        // kline
        $res = $raw[\\\"{$sym}__kline\\\"] ?? null;
        $k   = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? null) : null;

        // recent-trade
        $res = $raw[\\\"{$sym}__trade\\\"] ?? null;
        $t   = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? null) : null;

        // risk-limit
        $res = $raw[\\\"{$sym}__risk\\\"] ?? null;
        $r   = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? null) : null;

        // account-ratio
        $res = $raw[\\\"{$sym}__ratio\\\"] ?? null;
        $a   = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? null) : null;

        // mark-price-kline
        $res = $raw[\\\"{$sym}__mark\\\"] ?? null;
        $mk  = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? null) : null;

        // index-price-kline
        $res = $raw[\\\"{$sym}__index\\\"] ?? null;
        $ik  = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? null) : null;

        // premium-index-price-kline
        $res = $raw[\\\"{$sym}__premium\\\"] ?? null;
        $pk  = ($res && ($res[\\\'retCode\\\'] ?? -1) === 0) ? ($res[\\\'result\\\'][\\\'list\\\'][0] ?? null) : null;

        $result[$sym] = [
            \\\'symbol\\\'               => $sym,
            \\\'status\\\'               => $item[\\\'status\\\']                          ?? \\\'\\\',
            \\\'baseCoin\\\'             => $item[\\\'baseCoin\\\']                        ?? \\\'\\\',
            \\\'quoteCoin\\\'            => $item[\\\'quoteCoin\\\']                       ?? \\\'\\\',
            \\\'settleCoin\\\'           => $item[\\\'settleCoin\\\']                      ?? \\\'\\\',
            \\\'launchTime\\\'           => $item[\\\'launchTime\\\']                      ?? \\\'\\\',
            \\\'deliveryTime\\\'         => $item[\\\'deliveryTime\\\']                    ?? \\\'\\\',
            \\\'priceScale\\\'           => $item[\\\'priceScale\\\']                      ?? \\\'\\\',
            \\\'minLeverage\\\'          => $lf[\\\'minLeverage\\\']                       ?? \\\'\\\',
            \\\'maxLeverage\\\'          => $lf[\\\'maxLeverage\\\']                       ?? \\\'\\\',
            \\\'leverageStep\\\'         => $lf[\\\'leverageStep\\\']                      ?? \\\'\\\',
            \\\'minPrice\\\'             => $pf[\\\'minPrice\\\']                          ?? \\\'\\\',
            \\\'maxPrice\\\'             => $pf[\\\'maxPrice\\\']                          ?? \\\'\\\',
            \\\'tickSize\\\'             => $pf[\\\'tickSize\\\']                          ?? \\\'\\\',
            \\\'minOrderQty\\\'          => $ls[\\\'minOrderQty\\\']                       ?? \\\'\\\',
            \\\'maxOrderQty\\\'          => $ls[\\\'maxOrderQty\\\']                       ?? \\\'\\\',
            \\\'qtyStep\\\'              => $ls[\\\'qtyStep\\\']                           ?? \\\'\\\',
            \\\'fundingInterval\\\'      => $item[\\\'fundingInterval\\\']                 ?? \\\'\\\',
            \\\'copyTrading\\\'          => $item[\\\'copyTrading\\\']                     ?? \\\'\\\',
            \\\'unifiedMarginTrade\\\'   => ($item[\\\'unifiedMarginTrade\\\'] ? 1 : 0),
            \\\'deliveryFeeRate\\\'      => $item[\\\'deliveryFeeRate\\\']                 ?? \\\'\\\',
            \\\'postOnlyMaxOrderQty\\\'  => $item[\\\'lotSizeFilter\\\'][\\\'postOnlyMaxOrderQty\\\'] ?? \\\'\\\',
            \\\'upperLimitPrice\\\'      => $item[\\\'upperFundingRate\\\']                ?? \\\'\\\',
            \\\'lowerLimitPrice\\\'      => $item[\\\'lowerFundingRate\\\']                ?? \\\'\\\',
            \\\'time\\\'                 => (int)(microtime(true) * 1000),
            \\\'lastPrice\\\'            => $tk[\\\'lastPrice\\\']                         ?? \\\'\\\',
            \\\'prevPrice24h\\\'         => $tk[\\\'prevPrice24h\\\']                      ?? \\\'\\\',
            \\\'price24hPcnt\\\'         => $tk[\\\'price24hPcnt\\\']                      ?? \\\'\\\',
            \\\'highPrice24h\\\'         => $tk[\\\'highPrice24h\\\']                      ?? \\\'\\\',
            \\\'lowPrice24h\\\'          => $tk[\\\'lowPrice24h\\\']                       ?? \\\'\\\',
            \\\'openInterest\\\'         => $tk[\\\'openInterest\\\']                      ?? \\\'\\\',
            \\\'markPrice\\\'            => $tk[\\\'markPrice\\\']                         ?? \\\'\\\',
            \\\'indexPrice\\\'           => $tk[\\\'indexPrice\\\']                        ?? \\\'\\\',
            \\\'fundingRate\\\'          => $tk[\\\'fundingRate\\\']                       ?? \\\'\\\',
            \\\'prevPrice1h\\\'          => $tk[\\\'prevPrice1h\\\']                       ?? \\\'\\\',
            \\\'openInterestValue\\\'    => $tk[\\\'openInterestValue\\\']                 ?? \\\'\\\',
            \\\'turnover24h\\\'          => $tk[\\\'turnover24h\\\']                       ?? \\\'\\\',
            \\\'volume24h\\\'            => $tk[\\\'volume24h\\\']                         ?? \\\'\\\',
            \\\'nextFundingTime\\\'      => $tk[\\\'nextFundingTime\\\']                   ?? \\\'\\\',
            \\\'predictedDeliveryPrice\\\' => $tk[\\\'predictedDeliveryPrice\\\']          ?? \\\'\\\',
            \\\'basisRate\\\'            => $tk[\\\'basisRate\\\']                         ?? \\\'\\\',
            \\\'ask1Size\\\'             => $tk[\\\'ask1Size\\\']                          ?? \\\'\\\',
            \\\'bid1Price\\\'            => $tk[\\\'bid1Price\\\']                         ?? \\\'\\\',
            \\\'ask1Price\\\'            => $tk[\\\'ask1Price\\\']                         ?? \\\'\\\',
            \\\'bid1Size\\\'             => $tk[\\\'bid1Size\\\']                          ?? \\\'\\\',
            \\\'start\\\'                => $k[0]                                    ?? \\\'\\\',
            \\\'open\\\'                 => $k[1]                                    ?? \\\'\\\',
            \\\'high\\\'                 => $k[2]                                    ?? \\\'\\\',
            \\\'low\\\'                  => $k[3]                                    ?? \\\'\\\',
            \\\'close\\\'                => $k[4]                                    ?? \\\'\\\',
            \\\'volume\\\'               => $k[5]                                    ?? \\\'\\\',
            \\\'turnover\\\'             => $k[6]                                    ?? \\\'\\\',
            \\\'execId\\\'               => $t[\\\'execId\\\']                             ?? \\\'\\\',
            \\\'price\\\'                => $t[\\\'price\\\']                              ?? \\\'\\\',
            \\\'size\\\'                 => $t[\\\'size\\\']                               ?? \\\'\\\',
            \\\'side\\\'                 => $t[\\\'side\\\']                               ?? \\\'\\\',
            \\\'isBlockTrade\\\'         => ($t[\\\'isBlockTrade\\\'] ? 1 : 0),
            \\\'isAdlTrade\\\'           => ($t[\\\'isBlockTrade\\\'] ? 1 : 0),
            \\\'mPnL\\\'                 => $t[\\\'mPnL\\\']                               ?? \\\'\\\',
            \\\'riskId\\\'               => $r[\\\'id\\\']                                 ?? \\\'\\\',
            \\\'isLowestRisk\\\'         => $r[\\\'isLowestRisk\\\']                       ?? 0,
            \\\'maintenanceMargin\\\'    => $r[\\\'maintenanceMargin\\\']                  ?? \\\'\\\',
            \\\'initialMargin\\\'        => $r[\\\'initialMargin\\\']                      ?? \\\'\\\',
            \\\'limit\\\'                => $r[\\\'riskLimitValue\\\']                     ?? \\\'\\\',
            \\\'buyRatio\\\'             => $a[\\\'buyRatio\\\']                           ?? \\\'\\\',
            \\\'sellRatio\\\'            => $a[\\\'sellRatio\\\']                          ?? \\\'\\\',
            \\\'period\\\'               => 1,
            \\\'m_close\\\'              => $mk[4]                                   ?? \\\'\\\',
            \\\'i_close\\\'              => $ik[4]                                   ?? \\\'\\\',
            \\\'p_close\\\'              => $pk[4]                                   ?? \\\'\\\',
        ];
    }

    return $result;
}



$pdo     = get_db_connection();
$pdo_gnu = get_gnu_connection();
$server_ip = \\\'CLI_DAEMON\\\';

$cycle_count         = 0;
$last_market_refresh = 0;
$symbols             = [];

$stmt_hb   = null;
$stmt_kill = null;
$stmt_stop = null;
$stmt_best = null;

while (true) {
    $cycle_count++;

    try {
        $reconnected = false;
        if (!$pdo) {
            $pdo = get_db_connection();
            $reconnected = true;
        } else {
            try { $pdo->query(\\\"SELECT 1\\\"); }
            catch (Throwable $e) {
                $pdo = get_db_connection();
                $reconnected = true;
            }
        }
        if ($reconnected) {
            $stmt_hb = $stmt_kill = $stmt_stop = $stmt_best = null;
        }

        if ($pdo) {
            if (!$stmt_hb) {
                $stmt_hb = $pdo->prepare(\\\"
                    INSERT INTO daemon_record (
                        d_id, d_category, d_pid, d_status,
                        d_heartbeat, d_ip, d_start_time, d_memo, d_kill_flag
                    )
                    VALUES (
                        :id, \\\'BYBIT\\\', :pid, \\\'RUNNING\\\',
                        NOW(), :ip, NOW(), \\\'BYBIT LINEAR FUTURES GHOST\\\', 0
                    )
                    ON DUPLICATE KEY UPDATE
                        d_pid       = VALUES(d_pid),
                        d_status    = \\\'RUNNING\\\',
                        d_heartbeat = NOW(),
                        d_ip        = VALUES(d_ip),
                        d_memo      = VALUES(d_memo)
                \\\");
            }
            if (!$stmt_kill) {
                $stmt_kill = $pdo->prepare(\\\"SELECT d_kill_flag FROM daemon_record WHERE d_id = :id LIMIT 1\\\");
            }
            if (!$stmt_stop) {
                $stmt_stop = $pdo->prepare(\\\"
                    UPDATE daemon_record
                    SET d_status=\\\'STOPPED\\\', d_heartbeat=NOW(), d_pid=0
                    WHERE d_id=:id
                \\\");
            }

            $stmt_hb->execute([\\\':id\\\' => $DAEMON_ID, \\\':pid\\\' => getmypid(), \\\':ip\\\' => $server_ip]);

            $stmt_kill->execute([\\\':id\\\' => $DAEMON_ID]);
            $kill_flag = (int)($stmt_kill->fetchColumn() ?: 0);
            if ($kill_flag === 1) {
                $stmt_stop->execute([\\\':id\\\' => $DAEMON_ID]);
                exit(0);
            }

            // 종목 갱신 (1초마다)
            if (time() - $last_market_refresh >= 1 || empty($symbols)) {
                $tmp = [];
                // pdo_gnu 끊겼을 때만 재연결
                if (!$pdo_gnu) {
                    $pdo_gnu   = get_gnu_connection();
                    $stmt_best = null;
                } else {
                    try { $pdo_gnu->query(\\\"SELECT 1\\\"); }
                    catch (Throwable $e) {
                        $pdo_gnu   = get_gnu_connection();
                        $stmt_best = null;
                    }
                }
                if ($pdo_gnu instanceof PDO) {
                    if (!$stmt_best) {
                        $stmt_best = $pdo_gnu->prepare(\\\"
                            SELECT wr_subject FROM g5_write_daemon_kind_bybit
                            WHERE (x2_run = 1 OR x2_run = \\\'1\\\')
                        \\\");
                    }
                    $stmt_best->execute();
                    $best_rows = $stmt_best->fetchAll(PDO::FETCH_COLUMN);
                    if (is_array($best_rows)) {
                        foreach ($best_rows as $sym) {
                            $sym = strtoupper(trim((string)$sym));
                            if ($sym === \\\'\\\') continue;
                            if (strpos($sym, \\\'USDT\\\') === false && strpos($sym, \\\'-\\\') === false) {
                                $sym .= \\\'USDT\\\';
                            }
                            if (!in_array($sym, $tmp, true)) $tmp[] = $sym;
                        }
                    }
                }
                if ($tmp) {
                    $symbols = $tmp;
                    $last_market_refresh = time();
                } else {
                    $symbols = [];
                    sleep(10);
                    continue;
                }
            }

            if (!$symbols) {
                sleep(10);
                continue;
            }

            $at = date(\\\'Y-m-d H:i:s\\\');

            // 전체 종목 한번에 병렬 호출
            $all_data = collectAll($symbols);
            $rows = array_values(array_filter($all_data, fn($d) => !empty($d)));

            if (empty($rows)) {
                // 수집 데이터 없음 - 그냥 통과
            } else {
                // bulk INSERT - 전체 종목 한방 쿼리
                $placeholders = [];
                $params       = [];
                foreach ($rows as $i => $d) {
                    $placeholders[] = \\\"(
                        :symbol_{$i}, :status_{$i}, :baseCoin_{$i}, :quoteCoin_{$i}, :settleCoin_{$i},
                        :launchTime_{$i}, :deliveryTime_{$i}, :priceScale_{$i},
                        :minLeverage_{$i}, :maxLeverage_{$i}, :leverageStep_{$i},
                        :minPrice_{$i}, :maxPrice_{$i}, :tickSize_{$i},
                        :minOrderQty_{$i}, :maxOrderQty_{$i}, :qtyStep_{$i},
                        :fundingInterval_{$i}, :copyTrading_{$i}, :unifiedMarginTrade_{$i},
                        :deliveryFeeRate_{$i}, :postOnlyMaxOrderQty_{$i}, :upperLimitPrice_{$i}, :lowerLimitPrice_{$i},
                        :time_{$i}, NOW(),
                        :lastPrice_{$i}, :prevPrice24h_{$i}, :price24hPcnt_{$i},
                        :highPrice24h_{$i}, :lowPrice24h_{$i}, :openInterest_{$i},
                        :markPrice_{$i}, :indexPrice_{$i}, :fundingRate_{$i},
                        :prevPrice1h_{$i}, :openInterestValue_{$i}, :turnover24h_{$i}, :volume24h_{$i},
                        :nextFundingTime_{$i}, :predictedDeliveryPrice_{$i}, :basisRate_{$i},
                        :ask1Size_{$i}, :bid1Price_{$i}, :ask1Price_{$i}, :bid1Size_{$i},
                        :start_{$i}, :open_{$i}, :high_{$i}, :low_{$i}, :close_{$i}, :volume_{$i}, :turnover_{$i},
                        :execId_{$i}, :price_{$i}, :size_{$i}, :side_{$i}, :isBlockTrade_{$i}, :isAdlTrade_{$i}, :mPnL_{$i},
                        :riskId_{$i}, :isLowestRisk_{$i}, :maintenanceMargin_{$i}, :initialMargin_{$i}, :limit_{$i},
                        :buyRatio_{$i}, :sellRatio_{$i}, :period_{$i},
                        :m_close_{$i}, :i_close_{$i}, :p_close_{$i}
                    )\\\";
                    $params[\\\"symbol_{$i}\\\"]              = $d[\\\'symbol\\\'];
                    $params[\\\"status_{$i}\\\"]              = $d[\\\'status\\\'];
                    $params[\\\"baseCoin_{$i}\\\"]            = $d[\\\'baseCoin\\\'];
                    $params[\\\"quoteCoin_{$i}\\\"]           = $d[\\\'quoteCoin\\\'];
                    $params[\\\"settleCoin_{$i}\\\"]          = $d[\\\'settleCoin\\\'];
                    $params[\\\"launchTime_{$i}\\\"]          = $d[\\\'launchTime\\\'];
                    $params[\\\"deliveryTime_{$i}\\\"]        = $d[\\\'deliveryTime\\\'];
                    $params[\\\"priceScale_{$i}\\\"]          = $d[\\\'priceScale\\\'];
                    $params[\\\"minLeverage_{$i}\\\"]         = $d[\\\'minLeverage\\\'];
                    $params[\\\"maxLeverage_{$i}\\\"]         = $d[\\\'maxLeverage\\\'];
                    $params[\\\"leverageStep_{$i}\\\"]        = $d[\\\'leverageStep\\\'];
                    $params[\\\"minPrice_{$i}\\\"]            = $d[\\\'minPrice\\\'];
                    $params[\\\"maxPrice_{$i}\\\"]            = $d[\\\'maxPrice\\\'];
                    $params[\\\"tickSize_{$i}\\\"]            = $d[\\\'tickSize\\\'];
                    $params[\\\"minOrderQty_{$i}\\\"]         = $d[\\\'minOrderQty\\\'];
                    $params[\\\"maxOrderQty_{$i}\\\"]         = $d[\\\'maxOrderQty\\\'];
                    $params[\\\"qtyStep_{$i}\\\"]             = $d[\\\'qtyStep\\\'];
                    $params[\\\"fundingInterval_{$i}\\\"]     = $d[\\\'fundingInterval\\\'];
                    $params[\\\"copyTrading_{$i}\\\"]         = $d[\\\'copyTrading\\\'];
                    $params[\\\"unifiedMarginTrade_{$i}\\\"]  = $d[\\\'unifiedMarginTrade\\\'];
                    $params[\\\"deliveryFeeRate_{$i}\\\"]     = $d[\\\'deliveryFeeRate\\\'];
                    $params[\\\"postOnlyMaxOrderQty_{$i}\\\"] = $d[\\\'postOnlyMaxOrderQty\\\'];
                    $params[\\\"upperLimitPrice_{$i}\\\"]     = $d[\\\'upperLimitPrice\\\'];
                    $params[\\\"lowerLimitPrice_{$i}\\\"]     = $d[\\\'lowerLimitPrice\\\'];
                    $params[\\\"time_{$i}\\\"]                = $d[\\\'time\\\'];
                    $params[\\\"lastPrice_{$i}\\\"]           = $d[\\\'lastPrice\\\'];
                    $params[\\\"prevPrice24h_{$i}\\\"]        = $d[\\\'prevPrice24h\\\'];
                    $params[\\\"price24hPcnt_{$i}\\\"]        = $d[\\\'price24hPcnt\\\'];
                    $params[\\\"highPrice24h_{$i}\\\"]        = $d[\\\'highPrice24h\\\'];
                    $params[\\\"lowPrice24h_{$i}\\\"]         = $d[\\\'lowPrice24h\\\'];
                    $params[\\\"openInterest_{$i}\\\"]        = $d[\\\'openInterest\\\'];
                    $params[\\\"markPrice_{$i}\\\"]           = $d[\\\'markPrice\\\'];
                    $params[\\\"indexPrice_{$i}\\\"]          = $d[\\\'indexPrice\\\'];
                    $params[\\\"fundingRate_{$i}\\\"]         = $d[\\\'fundingRate\\\'];
                    $params[\\\"prevPrice1h_{$i}\\\"]         = $d[\\\'prevPrice1h\\\'];
                    $params[\\\"openInterestValue_{$i}\\\"]   = $d[\\\'openInterestValue\\\'];
                    $params[\\\"turnover24h_{$i}\\\"]         = $d[\\\'turnover24h\\\'];
                    $params[\\\"volume24h_{$i}\\\"]           = $d[\\\'volume24h\\\'];
                    $params[\\\"nextFundingTime_{$i}\\\"]     = $d[\\\'nextFundingTime\\\'];
                    $params[\\\"predictedDeliveryPrice_{$i}\\\"] = $d[\\\'predictedDeliveryPrice\\\'];
                    $params[\\\"basisRate_{$i}\\\"]           = $d[\\\'basisRate\\\'];
                    $params[\\\"ask1Size_{$i}\\\"]            = $d[\\\'ask1Size\\\'];
                    $params[\\\"bid1Price_{$i}\\\"]           = $d[\\\'bid1Price\\\'];
                    $params[\\\"ask1Price_{$i}\\\"]           = $d[\\\'ask1Price\\\'];
                    $params[\\\"bid1Size_{$i}\\\"]            = $d[\\\'bid1Size\\\'];
                    $params[\\\"start_{$i}\\\"]               = $d[\\\'start\\\'];
                    $params[\\\"open_{$i}\\\"]                = $d[\\\'open\\\'];
                    $params[\\\"high_{$i}\\\"]                = $d[\\\'high\\\'];
                    $params[\\\"low_{$i}\\\"]                 = $d[\\\'low\\\'];
                    $params[\\\"close_{$i}\\\"]               = $d[\\\'close\\\'];
                    $params[\\\"volume_{$i}\\\"]              = $d[\\\'volume\\\'];
                    $params[\\\"turnover_{$i}\\\"]            = $d[\\\'turnover\\\'];
                    $params[\\\"execId_{$i}\\\"]              = $d[\\\'execId\\\'];
                    $params[\\\"price_{$i}\\\"]               = $d[\\\'price\\\'];
                    $params[\\\"size_{$i}\\\"]                = $d[\\\'size\\\'];
                    $params[\\\"side_{$i}\\\"]                = $d[\\\'side\\\'];
                    $params[\\\"isBlockTrade_{$i}\\\"]        = $d[\\\'isBlockTrade\\\'];
                    $params[\\\"isAdlTrade_{$i}\\\"]          = $d[\\\'isAdlTrade\\\'];
                    $params[\\\"mPnL_{$i}\\\"]                = $d[\\\'mPnL\\\'];
                    $params[\\\"riskId_{$i}\\\"]              = $d[\\\'riskId\\\'];
                    $params[\\\"isLowestRisk_{$i}\\\"]        = $d[\\\'isLowestRisk\\\'];
                    $params[\\\"maintenanceMargin_{$i}\\\"]   = $d[\\\'maintenanceMargin\\\'];
                    $params[\\\"initialMargin_{$i}\\\"]       = $d[\\\'initialMargin\\\'];
                    $params[\\\"limit_{$i}\\\"]               = $d[\\\'limit\\\'];
                    $params[\\\"buyRatio_{$i}\\\"]            = $d[\\\'buyRatio\\\'];
                    $params[\\\"sellRatio_{$i}\\\"]           = $d[\\\'sellRatio\\\'];
                    $params[\\\"period_{$i}\\\"]              = $d[\\\'period\\\'];
                    $params[\\\"m_close_{$i}\\\"]             = $d[\\\'m_close\\\'];
                    $params[\\\"i_close_{$i}\\\"]             = $d[\\\'i_close\\\'];
                    $params[\\\"p_close_{$i}\\\"]             = $d[\\\'p_close\\\'];
                }

                $sql = \\\"
                    INSERT INTO daemon_bybit_Ticker (
                        symbol, status, baseCoin, quoteCoin, settleCoin,
                        launchTime, deliveryTime, priceScale,
                        minLeverage, maxLeverage, leverageStep,
                        minPrice, maxPrice, tickSize,
                        minOrderQty, maxOrderQty, qtyStep,
                        fundingInterval, copyTrading, unifiedMarginTrade,
                        deliveryFeeRate, postOnlyMaxOrderQty, upperLimitPrice, lowerLimitPrice,
                        time, updated_at,
                        lastPrice, prevPrice24h, price24hPcnt,
                        highPrice24h, lowPrice24h, openInterest,
                        markPrice, indexPrice, fundingRate,
                        prevPrice1h, openInterestValue, turnover24h, volume24h,
                        nextFundingTime, predictedDeliveryPrice, basisRate,
                        ask1Size, bid1Price, ask1Price, bid1Size,
                        `start`, `open`, `high`, `low`, `close`, volume, turnover,
                        execId, price, size, side, isBlockTrade, isAdlTrade, mPnL,
                        riskId, isLowestRisk, maintenanceMargin, initialMargin, `limit`,
                        buyRatio, sellRatio, period,
                        m_close, i_close, p_close
                    ) VALUES \\\" . implode(\\\',\\\', $placeholders) . \\\"
                    ON DUPLICATE KEY UPDATE
                        status               = VALUES(status),
                        baseCoin             = VALUES(baseCoin),
                        quoteCoin            = VALUES(quoteCoin),
                        settleCoin           = VALUES(settleCoin),
                        launchTime           = VALUES(launchTime),
                        deliveryTime         = VALUES(deliveryTime),
                        priceScale           = VALUES(priceScale),
                        minLeverage          = VALUES(minLeverage),
                        maxLeverage          = VALUES(maxLeverage),
                        leverageStep         = VALUES(leverageStep),
                        minPrice             = VALUES(minPrice),
                        maxPrice             = VALUES(maxPrice),
                        tickSize             = VALUES(tickSize),
                        minOrderQty          = VALUES(minOrderQty),
                        maxOrderQty          = VALUES(maxOrderQty),
                        qtyStep              = VALUES(qtyStep),
                        fundingInterval      = VALUES(fundingInterval),
                        copyTrading          = VALUES(copyTrading),
                        unifiedMarginTrade   = VALUES(unifiedMarginTrade),
                        deliveryFeeRate      = VALUES(deliveryFeeRate),
                        postOnlyMaxOrderQty  = VALUES(postOnlyMaxOrderQty),
                        upperLimitPrice      = VALUES(upperLimitPrice),
                        lowerLimitPrice      = VALUES(lowerLimitPrice),
                        time                 = VALUES(time),
                        updated_at           = NOW(),
                        lastPrice            = VALUES(lastPrice),
                        prevPrice24h         = VALUES(prevPrice24h),
                        price24hPcnt         = VALUES(price24hPcnt),
                        highPrice24h         = VALUES(highPrice24h),
                        lowPrice24h          = VALUES(lowPrice24h),
                        openInterest         = VALUES(openInterest),
                        markPrice            = VALUES(markPrice),
                        indexPrice           = VALUES(indexPrice),
                        fundingRate              = VALUES(fundingRate),
                        prevPrice1h              = VALUES(prevPrice1h),
                        openInterestValue        = VALUES(openInterestValue),
                        turnover24h              = VALUES(turnover24h),
                        volume24h                = VALUES(volume24h),
                        nextFundingTime          = VALUES(nextFundingTime),
                        predictedDeliveryPrice   = VALUES(predictedDeliveryPrice),
                        basisRate                = VALUES(basisRate),
                        ask1Size                 = VALUES(ask1Size),
                        bid1Price                = VALUES(bid1Price),
                        ask1Price                = VALUES(ask1Price),
                        bid1Size                 = VALUES(bid1Size),
                        `start`              = VALUES(`start`),
                        `open`               = VALUES(`open`),
                        `high`               = VALUES(`high`),
                        `low`                = VALUES(`low`),
                        `close`              = VALUES(`close`),
                        volume               = VALUES(volume),
                        turnover             = VALUES(turnover),
                        execId               = VALUES(execId),
                        price                = VALUES(price),
                        size                 = VALUES(size),
                        side                 = VALUES(side),
                        isBlockTrade         = VALUES(isBlockTrade),
                        isAdlTrade           = VALUES(isAdlTrade),
                        mPnL                 = VALUES(mPnL),
                        riskId               = VALUES(riskId),
                        isLowestRisk         = VALUES(isLowestRisk),
                        maintenanceMargin    = VALUES(maintenanceMargin),
                        initialMargin        = VALUES(initialMargin),
                        `limit`              = VALUES(`limit`),
                        buyRatio             = VALUES(buyRatio),
                        sellRatio            = VALUES(sellRatio),
                        period               = VALUES(period),
                        m_close              = VALUES(m_close),
                        i_close              = VALUES(i_close),
                        p_close              = VALUES(p_close)
                \\\";

                $stmt = $pdo->prepare($sql);
                $stmt->execute($params);
            }

        } else {
                sleep(5);
        }

        if ($cycle_count % 50 === 0 && function_exists(\\\'gc_collect_cycles\\\')) {
            gc_collect_cycles();
        }

    } catch (Throwable $e) {
        sleep(3);
    }

    sleep(30);
}
?>
#!/usr/bin/php
<?php
/**
 * ============================================================
 * 업비트 전체 시세 수집 CLI 데몬
 * - curl_multi 병렬 호출 방식
 * - gnu DB 루프 밖 1회 연결
 * - bulk INSERT 한방 쿼리
 * - echo/flush 전부 제거
 * ============================================================
 */

error_reporting(E_ALL);
ini_set(\\\'display_errors\\\', 1);
date_default_timezone_set(\\\'Asia/Seoul\\\');

$DAEMON_ID = pathinfo(__FILE__, PATHINFO_FILENAME);

if (php_sapi_name() !== \\\'cli\\\') {
    exit;
}

function get_db_connection() {
    try {
        $db_upbit = null;
        @include \\\'/home/www/DB/db_upbit.php\\\';
        if (!($db_upbit instanceof PDO)) return null;
        $pdo = $db_upbit;
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch (Throwable $e) {
        return null;
    }
}

function get_gnu_connection() {
    try {
        $db_gnu  = null;
        $pdo_gnu = null;
        $pdo     = null;
        @include \\\'/home/www/DB/db_gnu.php\\\';
        if ($db_gnu instanceof PDO) {
            $db_gnu->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $db_gnu;
        }
        if ($pdo_gnu instanceof PDO) {
            $pdo_gnu->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $pdo_gnu;
        }
        if ($pdo instanceof PDO) {
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $pdo;
        }
        return null;
    } catch (Throwable $e) {
        return null;
    }
}

// ============================================================
// curl_multi 병렬 호출
// ============================================================
function http_multi_get(array $urls): array {
    $mh      = curl_multi_init();
    $handles = [];

    foreach ($urls as $key => $url) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 8,
            CURLOPT_USERAGENT      => \\\'upbit-ghost\\\',
            CURLOPT_SSL_VERIFYPEER => false,
        ]);
        curl_multi_add_handle($mh, $ch);
        $handles[$key] = $ch;
    }

    $running = null;
    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh);
    } while ($running > 0);

    $results = [];
    foreach ($handles as $key => $ch) {
        $raw = curl_multi_getcontent($ch);
        $results[$key] = $raw ? json_decode($raw, true) : null;
        curl_multi_remove_handle($mh, $ch);
        curl_close($ch);
    }
    curl_multi_close($mh);

    return $results;
}

$api = require \\\'/home/www/DB/upbit_api_url.php\\\';
$API_TICKER    = $api[\\\'ticker\\\'] . \\\'?markets=\\\';
$API_ORDERBOOK = \\\'https://api.upbit.com/v1/orderbook?markets=\\\';

$pdo     = get_db_connection();
$pdo_gnu = get_gnu_connection();
$server_ip = \\\'CLI_DAEMON\\\';

$cycle_count         = 0;
$last_market_refresh = 0;
$krw                 = [];

$stmt_hb   = null;
$stmt_kill = null;
$stmt_stop = null;
$stmt_best = null;

while (true) {
    $cycle_count++;

    try {
        $reconnected = false;
        if (!$pdo) {
            $pdo = get_db_connection();
            $reconnected = true;
        } else {
            try { $pdo->query(\\\"SELECT 1\\\"); }
            catch (Throwable $e) {
                $pdo = get_db_connection();
                $reconnected = true;
            }
        }
        if ($reconnected) {
            $stmt_hb = $stmt_kill = $stmt_stop = $stmt_best = null;
        }

        if ($pdo) {
            if (!$stmt_hb) {
                $stmt_hb = $pdo->prepare(\\\"
                    INSERT INTO daemon_record (
                        d_id, d_category, d_pid, d_status,
                        d_heartbeat, d_ip, d_start_time, d_memo, d_kill_flag
                    )
                    VALUES (
                        :id, \\\'UPBIT\\\', :pid, \\\'RUNNING\\\',
                        NOW(), :ip, NOW(), \\\'UPBIT BOARD ONLY TICKER GHOST\\\', 0
                    )
                    ON DUPLICATE KEY UPDATE
                        d_pid       = VALUES(d_pid),
                        d_status    = \\\'RUNNING\\\',
                        d_heartbeat = NOW(),
                        d_ip        = VALUES(d_ip),
                        d_memo      = VALUES(d_memo)
                \\\");
            }
            if (!$stmt_kill) {
                $stmt_kill = $pdo->prepare(\\\"SELECT d_kill_flag FROM daemon_record WHERE d_id = :id LIMIT 1\\\");
            }
            if (!$stmt_stop) {
                $stmt_stop = $pdo->prepare(\\\"
                    UPDATE daemon_record
                    SET d_status=\\\'STOPPED\\\', d_heartbeat=NOW(), d_pid=0
                    WHERE d_id=:id
                \\\");
            }

            $stmt_hb->execute([\\\':id\\\' => $DAEMON_ID, \\\':pid\\\' => getmypid(), \\\':ip\\\' => $server_ip]);

            $stmt_kill->execute([\\\':id\\\' => $DAEMON_ID]);
            $kill_flag = (int)($stmt_kill->fetchColumn() ?: 0);
            if ($kill_flag === 1) {
                $stmt_stop->execute([\\\':id\\\' => $DAEMON_ID]);
                exit(0);
            }

            // 종목 갱신 (1초마다)
            if (time() - $last_market_refresh >= 1 || empty($krw)) {
                $tmp = [];
                if (!$pdo_gnu) {
                    $pdo_gnu   = get_gnu_connection();
                    $stmt_best = null;
                } else {
                    try { $pdo_gnu->query(\\\"SELECT 1\\\"); }
                    catch (Throwable $e) {
                        $pdo_gnu   = get_gnu_connection();
                        $stmt_best = null;
                    }
                }
                if ($pdo_gnu instanceof PDO) {
                    if (!$stmt_best) {
                        $stmt_best = $pdo_gnu->prepare(\\\"
                            SELECT wr_subject FROM g5_write_daemon_kind_upbit
                            WHERE (x2_run = 1 OR x2_run = \\\'1\\\')
                        \\\");
                    }
                    $stmt_best->execute();
                    $best_rows = $stmt_best->fetchAll(PDO::FETCH_COLUMN);
                    if (is_array($best_rows)) {
                        foreach ($best_rows as $sym) {
                            $sym = strtoupper(trim((string)$sym));
                            if ($sym === \\\'\\\') continue;
                            if (strpos($sym, \\\'-\\\') === false) {
                                $sym = \\\'KRW-\\\' . $sym;
                            }
                            if (strpos($sym, \\\'KRW-\\\') !== 0) continue;
                            if (!in_array($sym, $tmp, true)) $tmp[] = $sym;
                        }
                    }
                }
                if ($tmp) {
                    $krw = $tmp;
                    $last_market_refresh = time();
                } else {
                    $krw = [];
                    sleep(10);
                    continue;
                }
            }

            if (!$krw) {
                sleep(10);
                continue;
            }

            $at = date(\\\'Y-m-d H:i:s\\\');
            $ms = (int)(microtime(true) * 1000);

            // 티커 + 호가 한방에 동시 호출
            $market_str = implode(\\\',\\\', $krw);
            $raw = http_multi_get([
                \\\'ticker\\\'    => $API_TICKER    . $market_str,
                \\\'orderbook\\\' => $API_ORDERBOOK . $market_str,
            ]);

            $tks = $raw[\\\'ticker\\\'];
            $obs = $raw[\\\'orderbook\\\'];

            if (!$tks || !is_array($tks)) {
                sleep(3);
                continue;
            }

            // 호가 맵 구성
            $ob_map = [];
            if (is_array($obs)) {
                foreach ($obs as $o) {
                    if (isset($o[\\\'market\\\'])) {
                        $ob_map[$o[\\\'market\\\']] = $o;
                    }
                }
            }

            // bulk INSERT
            $placeholders = [];
            $params       = [];
            foreach ($tks as $i => $t) {
                $market = $t[\\\'market\\\'] ?? \\\'\\\';
                if ($market === \\\'\\\') continue;

                $ob = $ob_map[$market] ?? [];

                $placeholders[] = \\\"(
                    :market_{$i}, :trade_date_{$i}, :trade_time_{$i}, :trade_date_kst_{$i}, :trade_time_kst_{$i},
                    :opening_price_{$i}, :high_price_{$i}, :low_price_{$i}, :trade_price_{$i}, :prev_closing_price_{$i},
                    :change_{$i}, :change_price_{$i}, :change_rate_{$i}, :signed_change_price_{$i}, :signed_change_rate_{$i},
                    :trade_volume_{$i}, :acc_trade_volume_{$i}, :acc_trade_volume_24h_{$i}, :acc_trade_price_{$i}, :acc_trade_price_24h_{$i},
                    :highest_52_week_price_{$i}, :highest_52_week_date_{$i}, :lowest_52_week_price_{$i}, :lowest_52_week_date_{$i},
                    :collected_at_{$i}, :collected_ms_{$i},
                    :tr_trade_timestamp_{$i}, :tr_trade_price_{$i}, :tr_trade_volume_{$i}, :tr_ask_bid_{$i},
                    :tr_trade_date_utc_{$i}, :tr_trade_time_utc_{$i}, :tr_trade_date_kst_{$i}, :tr_trade_time_kst_{$i},
                    :tr_collected_at_{$i}, :tr_collected_ms_{$i},
                    :ob_timestamp_{$i}, :ob_total_ask_size_{$i}, :ob_total_bid_size_{$i}, :ob_units_{$i}
                )\\\";

                $params[\\\"market_{$i}\\\"]                = $market;
                $params[\\\"trade_date_{$i}\\\"]            = $t[\\\'trade_date\\\']              ?? \\\'\\\';
                $params[\\\"trade_time_{$i}\\\"]            = $t[\\\'trade_time\\\']              ?? \\\'\\\';
                $params[\\\"trade_date_kst_{$i}\\\"]        = $t[\\\'trade_date_kst\\\']          ?? \\\'\\\';
                $params[\\\"trade_time_kst_{$i}\\\"]        = $t[\\\'trade_time_kst\\\']          ?? \\\'\\\';
                $params[\\\"opening_price_{$i}\\\"]         = $t[\\\'opening_price\\\']           ?? 0;
                $params[\\\"high_price_{$i}\\\"]            = $t[\\\'high_price\\\']              ?? 0;
                $params[\\\"low_price_{$i}\\\"]             = $t[\\\'low_price\\\']               ?? 0;
                $params[\\\"trade_price_{$i}\\\"]           = $t[\\\'trade_price\\\']             ?? 0;
                $params[\\\"prev_closing_price_{$i}\\\"]    = $t[\\\'prev_closing_price\\\']      ?? 0;
                $params[\\\"change_{$i}\\\"]                = $t[\\\'change\\\']                  ?? \\\'\\\';
                $params[\\\"change_price_{$i}\\\"]          = $t[\\\'change_price\\\']            ?? 0;
                $params[\\\"change_rate_{$i}\\\"]           = $t[\\\'change_rate\\\']             ?? 0;
                $params[\\\"signed_change_price_{$i}\\\"]   = $t[\\\'signed_change_price\\\']     ?? 0;
                $params[\\\"signed_change_rate_{$i}\\\"]    = $t[\\\'signed_change_rate\\\']      ?? 0;
                $params[\\\"trade_volume_{$i}\\\"]          = $t[\\\'trade_volume\\\']            ?? 0;
                $params[\\\"acc_trade_volume_{$i}\\\"]      = $t[\\\'acc_trade_volume\\\']        ?? 0;
                $params[\\\"acc_trade_volume_24h_{$i}\\\"]  = $t[\\\'acc_trade_volume_24h\\\']    ?? 0;
                $params[\\\"acc_trade_price_{$i}\\\"]       = $t[\\\'acc_trade_price\\\']         ?? 0;
                $params[\\\"acc_trade_price_24h_{$i}\\\"]   = $t[\\\'acc_trade_price_24h\\\']     ?? 0;
                $params[\\\"highest_52_week_price_{$i}\\\"] = $t[\\\'highest_52_week_price\\\']   ?? 0;
                $params[\\\"highest_52_week_date_{$i}\\\"]  = $t[\\\'highest_52_week_date\\\']    ?? \\\'\\\';
                $params[\\\"lowest_52_week_price_{$i}\\\"]  = $t[\\\'lowest_52_week_price\\\']    ?? 0;
                $params[\\\"lowest_52_week_date_{$i}\\\"]   = $t[\\\'lowest_52_week_date\\\']     ?? \\\'\\\';
                $params[\\\"collected_at_{$i}\\\"]          = $at;
                $params[\\\"collected_ms_{$i}\\\"]          = $ms;
                $params[\\\"tr_trade_timestamp_{$i}\\\"]    = $t[\\\'trade_timestamp\\\']         ?? 0;
                $params[\\\"tr_trade_price_{$i}\\\"]        = $t[\\\'trade_price\\\']             ?? 0;
                $params[\\\"tr_trade_volume_{$i}\\\"]       = $t[\\\'trade_volume\\\']            ?? 0;
                $params[\\\"tr_ask_bid_{$i}\\\"]            = $t[\\\'ask_bid\\\']                 ?? \\\'\\\';
                $params[\\\"tr_trade_date_utc_{$i}\\\"]     = $t[\\\'trade_date\\\']              ?? \\\'\\\';
                $params[\\\"tr_trade_time_utc_{$i}\\\"]     = $t[\\\'trade_time\\\']              ?? \\\'\\\';
                $params[\\\"tr_trade_date_kst_{$i}\\\"]     = $t[\\\'trade_date_kst\\\']          ?? \\\'\\\';
                $params[\\\"tr_trade_time_kst_{$i}\\\"]     = $t[\\\'trade_time_kst\\\']          ?? \\\'\\\';
                $params[\\\"tr_collected_at_{$i}\\\"]       = $at;
                $params[\\\"tr_collected_ms_{$i}\\\"]       = $ms;
                $params[\\\"ob_timestamp_{$i}\\\"]          = $ob[\\\'timestamp\\\']              ?? 0;
                $params[\\\"ob_total_ask_size_{$i}\\\"]     = $ob[\\\'total_ask_size\\\']         ?? 0;
                $params[\\\"ob_total_bid_size_{$i}\\\"]     = $ob[\\\'total_bid_size\\\']         ?? 0;
                $params[\\\"ob_units_{$i}\\\"]              = isset($ob[\\\'orderbook_units\\\'])
                    ? json_encode($ob[\\\'orderbook_units\\\'], JSON_UNESCAPED_UNICODE)
                    : null;
            }

            if (!empty($placeholders)) {
                $sql = \\\"
                    INSERT INTO daemon_upbit_Ticker (
                        market, trade_date, trade_time, trade_date_kst, trade_time_kst,
                        opening_price, high_price, low_price, trade_price, prev_closing_price,
                        `change`, change_price, change_rate, signed_change_price, signed_change_rate,
                        trade_volume, acc_trade_volume, acc_trade_volume_24h, acc_trade_price, acc_trade_price_24h,
                        highest_52_week_price, highest_52_week_date, lowest_52_week_price, lowest_52_week_date,
                        collected_at, collected_ms,
                        tr_trade_timestamp, tr_trade_price, tr_trade_volume, tr_ask_bid,
                        tr_trade_date_utc, tr_trade_time_utc, tr_trade_date_kst, tr_trade_time_kst,
                        tr_collected_at, tr_collected_ms,
                        ob_timestamp, ob_total_ask_size, ob_total_bid_size, ob_units
                    ) VALUES \\\" . implode(\\\',\\\', $placeholders) . \\\"
                    ON DUPLICATE KEY UPDATE
                        trade_date            = VALUES(trade_date),
                        trade_time            = VALUES(trade_time),
                        trade_date_kst        = VALUES(trade_date_kst),
                        trade_time_kst        = VALUES(trade_time_kst),
                        opening_price         = VALUES(opening_price),
                        high_price            = VALUES(high_price),
                        low_price             = VALUES(low_price),
                        trade_price           = VALUES(trade_price),
                        prev_closing_price    = VALUES(prev_closing_price),
                        `change`              = VALUES(`change`),
                        change_price          = VALUES(change_price),
                        change_rate           = VALUES(change_rate),
                        signed_change_price   = VALUES(signed_change_price),
                        signed_change_rate    = VALUES(signed_change_rate),
                        trade_volume          = VALUES(trade_volume),
                        acc_trade_volume      = VALUES(acc_trade_volume),
                        acc_trade_volume_24h  = VALUES(acc_trade_volume_24h),
                        acc_trade_price       = VALUES(acc_trade_price),
                        acc_trade_price_24h   = VALUES(acc_trade_price_24h),
                        highest_52_week_price = VALUES(highest_52_week_price),
                        highest_52_week_date  = VALUES(highest_52_week_date),
                        lowest_52_week_price  = VALUES(lowest_52_week_price),
                        lowest_52_week_date   = VALUES(lowest_52_week_date),
                        collected_at          = VALUES(collected_at),
                        collected_ms          = VALUES(collected_ms),
                        tr_trade_timestamp    = VALUES(tr_trade_timestamp),
                        tr_trade_price        = VALUES(tr_trade_price),
                        tr_trade_volume       = VALUES(tr_trade_volume),
                        tr_ask_bid            = VALUES(tr_ask_bid),
                        tr_trade_date_utc     = VALUES(tr_trade_date_utc),
                        tr_trade_time_utc     = VALUES(tr_trade_time_utc),
                        tr_trade_date_kst     = VALUES(tr_trade_date_kst),
                        tr_trade_time_kst     = VALUES(tr_trade_time_kst),
                        tr_collected_at       = VALUES(tr_collected_at),
                        tr_collected_ms       = VALUES(tr_collected_ms),
                        ob_timestamp          = VALUES(ob_timestamp),
                        ob_total_ask_size     = VALUES(ob_total_ask_size),
                        ob_total_bid_size     = VALUES(ob_total_bid_size),
                        ob_units              = VALUES(ob_units)
                \\\";
                $stmt = $pdo->prepare($sql);
                $stmt->execute($params);
            }

        } else {
            sleep(5);
        }

        if ($cycle_count % 50 === 0 && function_exists(\\\'gc_collect_cycles\\\')) {
            gc_collect_cycles();
        }

    } catch (Throwable $e) {
        sleep(3);
    }

    sleep(30);
}
?>
WORK LINE
  • 2026-03-03 11:16:44
    * 방황 끝에 수정 완성인가?
    - 일단 수정 완료
    1. 바이비트
    2. 업비트
  • 2026-03-03 18:57:14
    * 뭐가 뭔지 모를 데몬 작업의 연속
    1. 여하튼 그럭저럭 완성본은 만들어졌다.
    2. 나머지 정리할 준비
확장 항목
루틴
  • 커피
요일
· 산책
· 러스 & 이너스 관리
· 기본청소 & 대청소
· 정리 & 정돈
세상일 작업 언제나 손이 만이 간다
버전: 1.0
http://m72.kr/GNU/bbs/board.php?bo_table=backup&wr_id=35
LINK
http://m72.kr/GNU/bbs/board.php?bo_table=backup&wr_id=36
LINK