format("Y-m-d H:i:s") . "
"; echo basename(__FILE__) . "
"; // 創建 OKX 的實例 $exchange = new ccxt\okx(array( 'enableRateLimit' => true, // 開啟速率限制 )); // 呼叫函式並獲取 coinList $coinList = getOkxPairs(); //----------基本設定---------- //----------基本設定---------- // 觀察清單 // $coinList = [ // 'BTC','ETH','SOL','TON','DOGE','XRP','PNUT','PEPE','UXLINK','X','ACT','1INCH','AAVE','ACE','ACH','ADA','AEVO','AGLD','AIDOGE','ALGO','ALPHA','APE','API3','APT','AR','ARB','ATH','ATOM','AUCTION','AVAX','AXS','BADGER','BAL','BAND','BAT','BCH','BICO','BIGTIME','BLUR','BNB','BNT','BOME','BONK','BONE','BRETT','BSV','CAT','CATI','CELO','CETUS','CFX','CHZ','COMP','CORE','CRO','CRV','CSPR','CTC','CVC','CVX','DGB','DOGS','DOT','DYDX','EGLD','EIGEN','ENJ','ENS','EOS','ETC','ETHW','ETHFI','FIL','FLM','FLOKI','FLOW','FOXY','FTM','FXS','GALA','GAS','GFT','GLM','GMT','GMX','GOAT','GODS','GRASS','GRT','HBAR','HMSTR','ICP','ICX','ID','IMX','INJ','IOST','IOTA','JOE','JST','JTO','JUP','KISHU','KNC','KSM','LDO','LINK','LOOKS','LPT','LQTY','LRC','LSK','LTC','LUNA','LUNC','MAGIC','MANA','MASK','MAX','MEME','MERL','METIS','MEW','MINA','MKR','MOODENG','MOVR','NEAR','NEIROETH','NEIRO','NEO','NFT','NMR','NOT','OM','ONDO','ONE','ONT','OP','ORBS','ORDI','PEOPLE','PERP','POL','POPCAT','PRCL','PUFFER','PYTH','QTUM','RACA','RAY','RDNT','RENDER','RON','RSR','RVN','SAND','SATS','SCR','SHIB','SLP','SNX','SSV','STORJ','STRK','STX','SUI','SUSHI','SWEAT','T','TAO','THETA','TIA','TNSR','TRB','TRX','TURBO','ULTI','UMA','UNI','USTC','VELO','VRA','W','WAXP','WIF','WLD','WOO','XCH','XLM','XTZ','YFI','YGG','ZENT','ZETA','ZIL','ZK','ZRO','ZRX' // ]; // $coinList = [ // 'BTC', // 'GGG', // 'SOL', // 'TON', // 'DOGE' // ]; $totalEq = totalEq(); $coinCount = count($coinList); // $amountInUSDT = ($totalEq) / $coinCount; // 下單金額 $amountInUSDT = 20; // 下單金額 //$amountInUSDT = 5; // 下單金額 echo "totalEq:$totalEq
"; echo "coinCount:$coinCount
"; echo "下單金額:$amountInUSDT
"; //----------第一部分---------- //----------第一部分---------- $markets = load_markets(); // 加載市場,查詢合約面值ctVal $fetch_positions = fetch_positions(); // 加載持倉 // 依序顯示觀察清單中的交易對 foreach ($coinList as $coin) { $symbol = $coin . '/USDT:USDT'; echo "

查看交易對: " . $symbol . "

"; $timeframe = '1d'; // K 線時間周期,1d 表示日線 $limit = 100; // 設定最多獲取最近100筆資料 try { // 獲取最近100筆 K 線資料 $ohlcv = $exchange->fetch_ohlcv($symbol, $timeframe, null, $limit); // 檢查資料是否正確返回 if (empty($ohlcv)) { throw new Exception("無法從 OKX 獲取資料,請檢查 API 配置或查詢參數"); } // 儲存所有資料及訊號資訊 $comparison_results = []; // 儲存比較結果 $processed_data = []; // 儲存處理後的 K 線資料 $latest_signal_data = null; // 儲存最新的訊號資料 $second_latest_signal_data = null; // 儲存倒數第二筆訊號資料 // 處理每一筆 K 線資料 for ($i = 0; $i < count($ohlcv); $i++) { // 當前日期與收盤價 $date = date('Y-m-d', $ohlcv[$i][0] / 1000); // 轉換為日期格式(將 Unix 時間戳轉為日期) $c0_close = $ohlcv[$i][4]; // 當前收盤價 (C[0]) // 31 天前的收盤價 $c31_close = "N/A"; // 預設為 "N/A" if ($i - 31 >= 0) { $c31_close = $ohlcv[$i - 31][4]; // 取得 31 天前的收盤價 } // 比較 C[0] 與 C[31] $comparison_result = "N/A"; // 預設比較結果為 "N/A" if ($c31_close !== "N/A") { // $comparison_result = ($c0_close > $c31_close) ? "1" : "0"; // 如果 C[0] 大於 C[31],設定為 "1",否則為 "0" if ($c0_close >= $c31_close * (1 + 0.02)) { $comparison_result = "1"; // 當 C[0] >= C[31] 的 102% 時 } elseif ($c0_close < $c31_close * (1 - 0.02)) { $comparison_result = "-1"; // 當 C[0] < C[31] 的 98% 時 } else { $comparison_result = "0"; } } // 記錄比較結果 $comparison_results[] = $comparison_result; // 上一筆比較結果 $previous_comparison_result = $i > 0 ? $comparison_results[$i - 1] : "N/A"; // 獲取上一筆的比較結果 // 訊號邏輯 // $signal = "N/A"; // 預設為 "N/A" // if ($previous_comparison_result === "0" && $comparison_result === "1") { // $signal = "LONG"; // 若上一筆為 "0" 且當前為 "1",設定為 "LONG" // } elseif ($previous_comparison_result === "1" && $comparison_result === "0") { // $signal = "SHORT"; // 若上一筆為 "1" 且當前為 "0",設定為 "SHORT" // } // 訊號邏輯 $signal = "N/A"; // 預設為 "N/A" if (($previous_comparison_result === "0" || $previous_comparison_result === "-1") && $comparison_result === "1") { $signal = "LONG"; // 從 0 或 -1 變 1,顯示 LONG } elseif (($previous_comparison_result === "0" || $previous_comparison_result === "1") && $comparison_result === "-1") { $signal = "SHORT"; // 從 0 或 1 變 -1,顯示 SHORT } // 儲存處理後的資料 $processed_data[] = [ 'date' => $date, // 日期 'c0_close' => $c0_close, // 當前收盤價 'c31_close' => $c31_close, // 31 天前的收盤價 'previous_comparison_result' => $previous_comparison_result, // 上一筆比較結果 'comparison_result' => $comparison_result, // 當前比較結果 'signal' => $signal // 訊號 ("LONG" 或 "SHORT") ]; // 更新最新與倒數第二筆訊號 if ($signal === "LONG" || $signal === "SHORT") { $second_latest_signal_data = $latest_signal_data; // 更新倒數第二筆訊號資料 $latest_signal_data = end($processed_data); // 更新最新的訊號資料 } } // 顯示昨天與今天的完整資料 echo "
昨天與今天的資料:
"; echo ""; echo ""; // 取出最後兩筆資料 $last_two_data = array_slice($processed_data, -2); foreach ($last_two_data as $data) { echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; } echo "
日期收盤價 (C[0])31 天前的收盤價 (C[31])上一筆比較結果比較結果訊號
" . $data['date'] . "" . $data['c0_close'] . "" . $data['c31_close'] . "" . $data['previous_comparison_result'] . "" . $data['comparison_result'] . "" . $data['signal'] . "
"; // 顯示最新與倒數第二筆帶有訊號的資料 echo "
最後兩筆訊號資料:
"; echo ""; echo ""; // 顯示最後兩筆帶有訊號的資料 foreach ([$second_latest_signal_data, $latest_signal_data] as $signal_data) { if ($signal_data !== null) { echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; } } echo "
日期收盤價 (C[0])31 天前的收盤價 (C[31])上一筆比較結果比較結果訊號
" . $signal_data['date'] . "" . $signal_data['c0_close'] . "" . $signal_data['c31_close'] . "" . $signal_data['previous_comparison_result'] . "" . $signal_data['comparison_result'] . "" . $signal_data['signal'] . "
"; // 取得昨天的日期 $yesterday_date = date('Y-m-d', strtotime('-1 day')); // 昨日日期 // 遍歷 processed_data 並找出 date 等於昨天的資料 foreach ($processed_data as $data) { if ($data['date'] === $yesterday_date) { // 如果日期等於昨天 // 設置下單訊號變數為 $data['signal'] $order_signal = $data['signal']; // 印出昨天日期的資料 echo "昨天的資料:\n"; echo "日期: " . $data['date'] . "\n"; // 日期 echo "收盤價 (C[0]): " . $data['c0_close'] . "\n"; // 當前收盤價 echo "訊號: " . $data['signal'] . "
"; // 訊號 ("LONG" 或 "SHORT") // 顯示下單訊號 echo "下單訊號: " . $order_signal . "
"; // 顯示下單訊號 } } $instId = $coin . '-USDT-SWAP'; $position = searchposition($instId); //定義marketposition、position if (isset($position)) { if ($position > 0) { $marketposition = 1; } elseif ($position < 0) { $marketposition = -1; } else { $position = 0; $marketposition = 0; } } else { $position = 0; $marketposition = 0; } echo "$instId 的 pos: " . $position . "
"; echo "最新報價: " . $c0_close . "
"; $searchmarkets = searchmarkets($instId); $ctVal = $searchmarkets['ctVal']; // 合約面值ctVal $minSz = $searchmarkets['minSz']; //最小下單數量 $lotSz = $searchmarkets['lotSz']; //精度 $precision = $searchmarkets['precision']; //精度 $amount = $amountInUSDT / $c0_close / $ctVal; // 計算下單數量 // 輸出變數的值 echo "合約面值 (ctVal): " . $ctVal . "
"; echo "最小下單數量 (minSz): " . $minSz . "
"; echo "精度 (lotSz): " . $lotSz . "
"; echo "精度 (precision): " . $precision . "
"; echo "下單數量 (amount): " . $amount . "
"; $final_amount = round($amount, $precision); //最後下單金額 echo "最後下單顆數 (final_amount): " . $final_amount . "
"; $min_amount = $c0_close * $ctVal * $minSz; echo "最小下單金額 (final_amount): " . $min_amount . "
"; // 判斷條件並設置 action if ($order_signal === "LONG" && $marketposition !== 1) { echo "LONG
"; try { echo "情況3/3:close
"; if ($position != 0) { $order = http_req("/api/v5/trade/close-position", "POST", array("instId" => $instId, "mgnMode" => "cross")); print_r($order); echo "
"; } } catch (Exception $e) { echo 'Error: ' . $e->getMessage() . "
\n"; } $final_amount = round($amount, $precision); //最後下單金額 if ($final_amount >= $minSz) { try { echo "情況1/3:long
"; $order = http_req("/api/v5/trade/order", "POST", array("instId" => $instId, "tdMode" => "cross", "side" => "buy", "ordType" => "market", "sz" => $final_amount)); print_r($order); echo "
"; } catch (Exception $e) { echo 'Error: ' . $e->getMessage() . "
\n"; } } else { echo "下單數量 < $minSz
"; } } elseif ($order_signal === "SHORT" && $marketposition !== -1) { echo "SHORT
"; try { echo "情況3/3:close
"; if ($position != 0) { $order = http_req("/api/v5/trade/close-position", "POST", array("instId" => $instId, "mgnMode" => "cross")); print_r($order); echo "
"; } } catch (Exception $e) { echo 'Error: ' . $e->getMessage() . "
\n"; } $final_amount = round($amount, $precision); //最後下單金額 if ($final_amount >= $minSz) { try { echo "情況2/3:short
"; $order = http_req("/api/v5/trade/order", "POST", array("instId" => $instId, "tdMode" => "cross", "side" => "sell", "ordType" => "market", "sz" => $final_amount)); print_r($order); echo "
"; } catch (Exception $e) { echo 'Error: ' . $e->getMessage() . "
\n"; } } else { echo "下單數量 < $minSz
"; } } else { echo "沒訊號
"; } } catch (\Exception $e) { echo '錯誤: ' . $e->getMessage() . "\n"; // 顯示錯誤訊息 } } $execution_time = microtime(true) - $start_time; // 計算執行時間 echo "程式執行時間: $execution_time 秒
"; // 輸出執行時間 // 取得緩衝區內容 $content = ob_get_contents(); $currentHour = (int)date("H"); // 僅在當前時間為 0、8 或 16 時儲存 if (in_array($currentHour, [0, 8, 16], true)) { $fileName = __DIR__ . "/../log/" . basename(__FILE__) . "_" . $currentHour . ".html"; if (file_put_contents($fileName, $content) !== false) { echo "內容已成功保存至 $fileName"; } else { echo "儲存失敗,請檢查檔案路徑或權限。"; } } else { echo "目前時間非 0、8 或 16,未進行儲存。"; } //基底curl function http_req($endpoint, $method, $params) { global $apiKey, $secret, $passphrase; $curl = curl_init(); if ($method == "GET") { $endpoint .= '?' . $params; $body = ''; // 如果請求沒有主體,將為空字符串 } $timestamp = gmdate('Y-m-d\TH:i:s\Z'); // 獲取當前時間戳,不包含毫秒 if ($method == "POST") { $body = json_encode($params); //$body = ''; // 如果請求沒有主體,將為空字符串 } $params_for_signature = $timestamp . $method . $endpoint . $body; $signature = base64_encode(hash_hmac('sha256', $params_for_signature, $secret, true)); curl_setopt_array($curl, array( CURLOPT_URL => "https://www.okx.com" . $endpoint, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => array( "OK-ACCESS-KEY: $apiKey", "OK-ACCESS-SIGN: $signature", "OK-ACCESS-TIMESTAMP: $timestamp", "OK-ACCESS-PASSPHRASE: $passphrase", "Content-Type: application/json" ), )); if ($method == "GET") { curl_setopt($curl, CURLOPT_HTTPGET, true); } $data = json_decode(curl_exec($curl), true); //echo "
";
    //print_r($data);
    //echo "
"; curl_close($curl); return $data; } //全部持倉 function fetch_positions() { $endpoint = "/api/v5/account/positions"; $method = "GET"; $params = "instType=SWAP"; $data = http_req($endpoint, $method, $params); return $data; // 如果未找到目標儀器,則返回錯誤訊息 } //單一 symbol 持倉 function searchposition($instId) { global $fetch_positions; //echo "
";
    //print_r($fetch_positions);
    //echo "
"; foreach ($fetch_positions['data'] as $posData) { // 使用不同的名稱,避免衝突 if ($posData['instId'] === $instId) { $pos = $posData['pos']; return $pos; } } return null; // 如果未找到则返回 null } //單一 symbol 市場資訊 function searchmarkets($instId) { global $markets; foreach ($markets['data'] as $market) { if ($market['instId'] === $instId) { $precision = -log10($market['lotSz']); //精度 $result = array( 'ctVal' => $market['ctVal'], 'minSz' => $market['minSz'], 'lotSz' => $market['lotSz'], 'precision' => $precision, ); return $result; // 返回包含 ctVal、minSz 和 lotSz 值的陣列 } } return "Instrument not found"; // 如果未找到目標儀器,則返回錯誤訊息 } //totalEq function totalEq() { $endpoint = "/api/v5/account/balance"; $method = "GET"; $params = 'null'; $data = http_req($endpoint, $method, $params); $totalEq = $data['data'][0]['totalEq']; return $totalEq; // 如果未找到目標儀器,則返回錯誤訊息 } //基礎資料 function load_markets() { $endpoint = "/api/v5/public/instruments"; $method = "GET"; $params = "instType=SWAP"; $data = http_req($endpoint, $method, $params); return $data; // 如果未找到目標儀器,則返回錯誤訊息 } /** * 獲取 OKX 交易所的所有交易對 */ function getOkxPairs() { global $exchange; try { // 獲取所有交易對的市場資料 $markets = $exchange->load_markets(); // echo "
";
    // print_r($markets);
    // echo "
"; // 檢查資料是否正確返回 if (empty($markets)) { throw new Exception("無法從 OKX 獲取市場資料"); } $filteredMarkets = []; // 用於存放篩選後的交易對資料 $baseCurrencies = []; // 儲存基礎貨幣清單 // 篩選所有以 :USDT 結尾且不包含 USDC 的交易對並收集相關資料 foreach ($markets as $symbol => $market) { if (substr($symbol, -5) === ':USDT' && strpos($symbol, 'USDC') === false) { // 排除包含 USDC 的交易對 $createdTime = isset($market['created']) ? $market['created'] : 0; // 默認為 0,如果沒有創建時間 $filteredMarkets[] = [ 'symbol' => $symbol, 'base' => $market['base'], 'created' => $createdTime, ]; } } // 根據創建時間進行排序,最近的交易對排在最前面 usort($filteredMarkets, function ($a, $b) { return $a['created'] - $b['created']; }); // 根據 filteredMarkets 構建基礎貨幣清單 foreach ($filteredMarkets as $market) { $baseCurrencies[] = $market['base']; } // 去除重複的基礎貨幣,但保留出現順序 $baseCurrencies = array_values(array_unique($baseCurrencies)); // 將 coinList 儲存為陣列 $coinList = $baseCurrencies; // 現在 $coinList 是一個基礎貨幣的陣列 // 返回 coinList 陣列 return $coinList; } catch (Exception $e) { echo '錯誤: ' . $e->getMessage(); } } ?>