CORE TERMINAL
올드보이 & 마리아 백업
바이비트 API 실시간 플렛폼 수집 데몬, Ver.2.2
DATE: 2026-03-03 10:10
핵심 항목
테마2.0
내용
* 바이비트 API 실시간 플렛폼 수집 데몬, Ver.2.2
- http://m72.kr/GNU/bbs/board.php?bo_table=backup&wr_id=30
1. 기존 단순 무식 완성형 데몬 업그레이드
가. 속도 개선
ㄱ. 그누보드 종목 호출력 : 기존 단일 호출 -> 일괄 호출 변경
- http://m72.kr/GNU/bbs/board.php?bo_table=backup&wr_id=30
1. 기존 단순 무식 완성형 데몬 업그레이드
가. 속도 개선
ㄱ. 그누보드 종목 호출력 : 기존 단일 호출 -> 일괄 호출 변경
추가 내용
#!/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;
}
echo \\\\\\\"==================================================\\\\\\\\n\\\\\\\";
echo \\\\\\\"[{$DAEMON_ID}] 바이비트 선물 데몬이 시작되었습니다.\\\\\\\\n\\\\\\\";
echo \\\\\\\"PID : \\\\\\\" . getmypid() . \\\\\\\"\\\\\\\\n\\\\\\\";
echo \\\\\\\"상태는 daemon_record 테이블에서 확인할 수 있습니다.\\\\\\\\n\\\\\\\";
echo \\\\\\\"종료 시에는 d_kill_flag=1 또는 프로세스 kill 사용.\\\\\\\\n\\\\\\\";
echo \\\\\\\"==================================================\\\\\\\\n\\\\\\\";
$pdo = get_db_connection();
$server_ip = \\\\\\\'CLI_DAEMON\\\\\\\';
$cycle_count = 0;
$last_market_refresh = 0;
$symbols = [];
$stmt_hb = null;
$stmt_kill = null;
$stmt_stop = null;
$stmt_ins = 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_ins = 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]);
echo \\\\\\\"\\\\\\\\n-> [STOP] d_kill_flag=1 감지. 정상 종료합니다.\\\\\\\\n\\\\\\\";
exit(0);
}
// 종목 갱신 (1초마다)
if (time() - $last_market_refresh >= 1 || empty($symbols)) {
$tmp = [];
$pdo_gnu = get_gnu_connection();
if ($pdo_gnu instanceof PDO) {
$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();
echo \\\\\\\"-> [INFO] 보드 종목 갱신 완료 (\\\\\\\" . count($symbols) . \\\\\\\"개)\\\\\\\\n\\\\\\\";
} else {
$symbols = [];
echo \\\\\\\"-> [WARN] 보드 실행 종목(x2_run=1) 없음/DB연결실패. 10초 대기...\\\\\\\\n\\\\\\\";
flush();
sleep(10);
continue;
}
}
if (!$symbols) {
echo \\\\\\\"-> [WARN] 수집 종목 없음. 10초 대기...\\\\\\\\n\\\\\\\";
flush();
sleep(10);
continue;
}
if (!$stmt_ins) {
$stmt_ins = $pdo->prepare(\\\\\\\"
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 (
: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, NOW(),
: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
)
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)
\\\\\\\");
if ($stmt_ins === false || !($stmt_ins instanceof PDOStatement)) {
$err = $pdo->errorInfo();
echo \\\\\\\"\\\\\\\\n-> [ERROR] stmt_ins prepare 실패: \\\\\\\" . ($err[2] ?? \\\\\\\'unknown\\\\\\\') . \\\\\\\"\\\\\\\\n\\\\\\\";
$stmt_ins = null;
flush(); sleep(5); continue;
}
}
$at = date(\\\\\\\'Y-m-d H:i:s\\\\\\\');
// 전체 종목 한번에 병렬 호출
$all_data = collectAll($symbols);
foreach ($all_data as $symbol => $d) {
if (empty($d)) {
echo \\\\\\\"\\\\\\\\n-> [SKIP] {$symbol} API 실패\\\\\\\\n\\\\\\\";
continue;
}
$stmt_ins->execute([
\\\\\\\':symbol\\\\\\\' => $d[\\\\\\\'symbol\\\\\\\'],
\\\\\\\':status\\\\\\\' => $d[\\\\\\\'status\\\\\\\'],
\\\\\\\':baseCoin\\\\\\\' => $d[\\\\\\\'baseCoin\\\\\\\'],
\\\\\\\':quoteCoin\\\\\\\' => $d[\\\\\\\'quoteCoin\\\\\\\'],
\\\\\\\':settleCoin\\\\\\\' => $d[\\\\\\\'settleCoin\\\\\\\'],
\\\\\\\':launchTime\\\\\\\' => $d[\\\\\\\'launchTime\\\\\\\'],
\\\\\\\':deliveryTime\\\\\\\' => $d[\\\\\\\'deliveryTime\\\\\\\'],
\\\\\\\':priceScale\\\\\\\' => $d[\\\\\\\'priceScale\\\\\\\'],
\\\\\\\':minLeverage\\\\\\\' => $d[\\\\\\\'minLeverage\\\\\\\'],
\\\\\\\':maxLeverage\\\\\\\' => $d[\\\\\\\'maxLeverage\\\\\\\'],
\\\\\\\':leverageStep\\\\\\\' => $d[\\\\\\\'leverageStep\\\\\\\'],
\\\\\\\':minPrice\\\\\\\' => $d[\\\\\\\'minPrice\\\\\\\'],
\\\\\\\':maxPrice\\\\\\\' => $d[\\\\\\\'maxPrice\\\\\\\'],
\\\\\\\':tickSize\\\\\\\' => $d[\\\\\\\'tickSize\\\\\\\'],
\\\\\\\':minOrderQty\\\\\\\' => $d[\\\\\\\'minOrderQty\\\\\\\'],
\\\\\\\':maxOrderQty\\\\\\\' => $d[\\\\\\\'maxOrderQty\\\\\\\'],
\\\\\\\':qtyStep\\\\\\\' => $d[\\\\\\\'qtyStep\\\\\\\'],
\\\\\\\':fundingInterval\\\\\\\' => $d[\\\\\\\'fundingInterval\\\\\\\'],
\\\\\\\':copyTrading\\\\\\\' => $d[\\\\\\\'copyTrading\\\\\\\'],
\\\\\\\':unifiedMarginTrade\\\\\\\' => $d[\\\\\\\'unifiedMarginTrade\\\\\\\'],
\\\\\\\':deliveryFeeRate\\\\\\\' => $d[\\\\\\\'deliveryFeeRate\\\\\\\'],
\\\\\\\':postOnlyMaxOrderQty\\\\\\\' => $d[\\\\\\\'postOnlyMaxOrderQty\\\\\\\'],
\\\\\\\':upperLimitPrice\\\\\\\' => $d[\\\\\\\'upperLimitPrice\\\\\\\'],
\\\\\\\':lowerLimitPrice\\\\\\\' => $d[\\\\\\\'lowerLimitPrice\\\\\\\'],
\\\\\\\':time\\\\\\\' => $d[\\\\\\\'time\\\\\\\'],
\\\\\\\':lastPrice\\\\\\\' => $d[\\\\\\\'lastPrice\\\\\\\'],
\\\\\\\':prevPrice24h\\\\\\\' => $d[\\\\\\\'prevPrice24h\\\\\\\'],
\\\\\\\':price24hPcnt\\\\\\\' => $d[\\\\\\\'price24hPcnt\\\\\\\'],
\\\\\\\':highPrice24h\\\\\\\' => $d[\\\\\\\'highPrice24h\\\\\\\'],
\\\\\\\':lowPrice24h\\\\\\\' => $d[\\\\\\\'lowPrice24h\\\\\\\'],
\\\\\\\':openInterest\\\\\\\' => $d[\\\\\\\'openInterest\\\\\\\'],
\\\\\\\':markPrice\\\\\\\' => $d[\\\\\\\'markPrice\\\\\\\'],
\\\\\\\':indexPrice\\\\\\\' => $d[\\\\\\\'indexPrice\\\\\\\'],
\\\\\\\':fundingRate\\\\\\\' => $d[\\\\\\\'fundingRate\\\\\\\'],
\\\\\\\':prevPrice1h\\\\\\\' => $d[\\\\\\\'prevPrice1h\\\\\\\'],
\\\\\\\':openInterestValue\\\\\\\' => $d[\\\\\\\'openInterestValue\\\\\\\'],
\\\\\\\':turnover24h\\\\\\\' => $d[\\\\\\\'turnover24h\\\\\\\'],
\\\\\\\':volume24h\\\\\\\' => $d[\\\\\\\'volume24h\\\\\\\'],
\\\\\\\':nextFundingTime\\\\\\\' => $d[\\\\\\\'nextFundingTime\\\\\\\'],
\\\\\\\':predictedDeliveryPrice\\\\\\\' => $d[\\\\\\\'predictedDeliveryPrice\\\\\\\'],
\\\\\\\':basisRate\\\\\\\' => $d[\\\\\\\'basisRate\\\\\\\'],
\\\\\\\':ask1Size\\\\\\\' => $d[\\\\\\\'ask1Size\\\\\\\'],
\\\\\\\':bid1Price\\\\\\\' => $d[\\\\\\\'bid1Price\\\\\\\'],
\\\\\\\':ask1Price\\\\\\\' => $d[\\\\\\\'ask1Price\\\\\\\'],
\\\\\\\':bid1Size\\\\\\\' => $d[\\\\\\\'bid1Size\\\\\\\'],
\\\\\\\':start\\\\\\\' => $d[\\\\\\\'start\\\\\\\'],
\\\\\\\':open\\\\\\\' => $d[\\\\\\\'open\\\\\\\'],
\\\\\\\':high\\\\\\\' => $d[\\\\\\\'high\\\\\\\'],
\\\\\\\':low\\\\\\\' => $d[\\\\\\\'low\\\\\\\'],
\\\\\\\':close\\\\\\\' => $d[\\\\\\\'close\\\\\\\'],
\\\\\\\':volume\\\\\\\' => $d[\\\\\\\'volume\\\\\\\'],
\\\\\\\':turnover\\\\\\\' => $d[\\\\\\\'turnover\\\\\\\'],
\\\\\\\':execId\\\\\\\' => $d[\\\\\\\'execId\\\\\\\'],
\\\\\\\':price\\\\\\\' => $d[\\\\\\\'price\\\\\\\'],
\\\\\\\':size\\\\\\\' => $d[\\\\\\\'size\\\\\\\'],
\\\\\\\':side\\\\\\\' => $d[\\\\\\\'side\\\\\\\'],
\\\\\\\':isBlockTrade\\\\\\\' => $d[\\\\\\\'isBlockTrade\\\\\\\'],
\\\\\\\':isAdlTrade\\\\\\\' => $d[\\\\\\\'isAdlTrade\\\\\\\'],
\\\\\\\':mPnL\\\\\\\' => $d[\\\\\\\'mPnL\\\\\\\'],
\\\\\\\':riskId\\\\\\\' => $d[\\\\\\\'riskId\\\\\\\'],
\\\\\\\':isLowestRisk\\\\\\\' => $d[\\\\\\\'isLowestRisk\\\\\\\'],
\\\\\\\':maintenanceMargin\\\\\\\' => $d[\\\\\\\'maintenanceMargin\\\\\\\'],
\\\\\\\':initialMargin\\\\\\\' => $d[\\\\\\\'initialMargin\\\\\\\'],
\\\\\\\':limit\\\\\\\' => $d[\\\\\\\'limit\\\\\\\'],
\\\\\\\':buyRatio\\\\\\\' => $d[\\\\\\\'buyRatio\\\\\\\'],
\\\\\\\':sellRatio\\\\\\\' => $d[\\\\\\\'sellRatio\\\\\\\'],
\\\\\\\':period\\\\\\\' => $d[\\\\\\\'period\\\\\\\'],
\\\\\\\':m_close\\\\\\\' => $d[\\\\\\\'m_close\\\\\\\'],
\\\\\\\':i_close\\\\\\\' => $d[\\\\\\\'i_close\\\\\\\'],
\\\\\\\':p_close\\\\\\\' => $d[\\\\\\\'p_close\\\\\\\'],
]);
}
echo \\\\\\\".\\\\\\\";
if ($cycle_count % 10 === 0) {
echo \\\\\\\" <Running... Time: {$at} / 종목수: \\\\\\\" . count($symbols) . \\\\\\\">\\\\\\\\n\\\\\\\";
}
flush();
} else {
echo \\\\\\\"-> [WARN] DB 연결 실패. 5초 대기...\\\\\\\\n\\\\\\\";
flush();
sleep(5);
}
if ($cycle_count % 50 === 0 && function_exists(\\\\\\\'gc_collect_cycles\\\\\\\')) {
gc_collect_cycles();
}
} catch (Throwable $e) {
$log = date(\\\\\\\'[Y-m-d H:i:s] \\\\\\\') . \\\\\\\"ERROR: \\\\\\\" . $e->getMessage();
echo \\\\\\\"\\\\\\\\n-> $log\\\\\\\\n\\\\\\\";
flush();
sleep(3);
}
sleep(30);
}
최근 "데몬" 데이터