0

I'm trying to get data in the order of bybit -> cloudflare worker -> google scripts. I got the value from bybit to the worker via API, but when I get the value from the worker via google scripts, I always get only the initial value. There is a phenomenon where I can't get the new data from bybit.

I'll share the workers' code and the google script code.

// Workers code

export default {
  async fetch(request) {
    const API_KEY = "";  
    const API_SECRET = "";  
    const endpoint = "https://api.bybit.com/v5/position/closed-pnl";  
    const category = "linear";  // USDT 선물  
    const symbol = "BTCUSDT";  // 원하는 종목  
    const recvWindow = "5000";  
    const now = Date.now();  
    // 📌 임시로 특정 날짜 지정 (예: 2024년 2월 1일)
    const startTime = 1740441600000; // ✅ 필요 시 변경 가능 (추후 삭제 예정)
    const endTime = 1740787200000;
    const timestamp = now.toString();
    // 📌 Bybit 규칙: 파라미터를 알파벳 순으로 정렬해야 함!
    const params = [
      `api_key=${API_KEY}`,
      `category=${category}`,
      `endTime=${endTime}`,
      `recv_window=${recvWindow}`,
      `startTime=${startTime}`,
      `symbol=${symbol}`,
      `timestamp=${timestamp}`
    ].sort().join("&");
    const signature = await generateSignature(API_SECRET, params);
    try {
      const response = await fetch(`${endpoint}?${params}&sign=${signature}`, {
        method: "GET",
        headers: { "Content-Type": "application/json" }
      });
      const result = await response.json();
      console.log(`📌 최신 데이터 요청 결과:`, JSON.stringify(result, null, 2));
      if (result.retCode === 0) {
        const processedData = (result.result.list || []).map(item => ({
          symbol: item.symbol,
          leverage: item.leverage,
          updatedTime: convertToKST(item.updatedTime), // ✅ 한국 시간 변환 적용
          side: item.side === "Buy" ? "Long" : "Short", // ✅ Buy → Long, Sell → Short 변환
          closedPnl: item.closedPnl,
          qty: item.qty
        }));
        return new Response(JSON.stringify(processedData), { headers: { "Content-Type": "application/json" } });
      } else {
        console.warn(`🚨 요청 실패: ${result.retMsg}`);
      }
    } catch (error) {
      console.error(`🚨 요청 중 에러 발생: ${error.message}`);
    }
    return new Response(JSON.stringify([]), { headers: { "Content-Type": "application/json" } });
  }
};
// 📌 HMAC SHA-256 서명 생성
async function generateSignature(secret, payload) {
  const encoder = new TextEncoder();
  const key = await crypto.subtle.importKey(
    "raw",
    encoder.encode(secret),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"]
  );
  const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
  return [...new Uint8Array(signature)].map(b => b.toString(16).padStart(2, "0")).join("");
}
// 📌 한국 시간(KST) 변환 함수
function convertToKST(timestamp) {
  const date = new Date(Number(timestamp)); // ✅ 숫자로 변환 후 Date 객체 생성
  if (isNaN(date.getTime())) return "Invalid Date"; // 🚨 변환 실패 시 Invalid Date 반환
  return date.toLocaleString("ko-KR", { timeZone: "Asia/Seoul" }); // ✅ 한국 시간 변환
}

//google scripts code

function updateBybitData() {
  const CLOUDFLARE_URL = "https://frosty-waterfall-ca94.gizldaos100.workers.dev/"; // Cloudflare Worker URL
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("BybitPnL");
  if (!sheet) {
    Logger.log("🚨 오류: 'BybitPnL' 시트를 찾을 수 없습니다!");
    return;
  }
  const options = {
    muteHttpExceptions: true,
    headers: { 
      "User-Agent": "Mozilla/5.0 (compatible; GoogleAppsScript)",
      "Cache-Control": "no-cache" // 🚀 캐시 무시하고 최신 데이터 요청
    }
  };
  // ✅ API 호출
  const response = UrlFetchApp.fetch(CLOUDFLARE_URL, options);
  Utilities.sleep(2000); // 2초 기다리기
  const statusCode = response.getResponseCode();
  Logger.log(`📌 HTTP 응답 상태 코드: ${statusCode}`);
  if (statusCode !== 200) {
    Logger.log(`🚨 오류: API 응답이 200이 아님! (${statusCode})`);
    return;
  }
  const contentText = response.getContentText();
  Logger.log(`📌 Cloudflare 응답 데이터: ${contentText}`);
  let jsonData;
  try {
    jsonData = JSON.parse(contentText);
  } catch (error) {
    Logger.log(`🚨 JSON 파싱 오류: ${error.message}`);
    return;
  }
  if (!Array.isArray(jsonData) || jsonData.length === 0) {
    Logger.log("⚠️ 가져온 데이터가 없거나 응답 형식이 올바르지 않습니다.");
    return;
  }
  Logger.log(`✅ 가져온 데이터 개수: ${jsonData.length}`);
  const lastRow = sheet.getLastRow();
  sheet.getRange(lastRow + 1, 1, jsonData.length, 6).setValues(
    jsonData.map(entry => [
      entry.symbol,
      entry.leverage,
      entry.updatedTime,
      entry.side,
      entry.closedPnl,
      entry.qty
    ])
  );
  Logger.log("✅ Google Sheets 업데이트 완료!");
}

// Workers log

📌 최신 데이터 요청 결과: {
  "retCode": 0,
  "retMsg": "OK",
  "result": {
    "nextPageCursor": "efbb3171-75c1-4b57-b53c-bcfe972fd619%3A1740442479423%2Cefbb3171-75c1-4b57-b53c-bcfe972fd619%3A1740442479423",
    "category": "linear",
    "list": [
      {
        "symbol": "BTCUSDT",
        "orderType": "Market",
        "leverage": "7",
        "updatedTime": "1740442479423",
        "side": "Buy",
        "orderId": "efbb3171-75c1-4b57-b53c-bcfe972fd619",
        "closedPnl": "47.92136761",
        "avgEntryPrice": "92327.7",
        "qty": "0.034",
        "cumEntryValue": "3139.1418",
        "createdTime": "1740442479419",
        "orderPrice": "91841.1",
        "closedSize": "0.034",
        "avgExitPrice": "90846.8",
        "execType": "Trade",
        "fillCount": "2",
        "cumExitValue": "3088.7912"
      }
    ]
  },
  "retExtInfo": {},
  "time": 1741581760788
}

// google appscripts log

오후 1:43:31  알림  실행이 시작됨
오후 1:43:33  정보  📌 HTTP 응답 상태 코드: 200
오후 1:43:33  정보  📌 Cloudflare 응답 데이터: []
오후 1:43:33  정보  ⚠️ 가져온 데이터가 없거나 응답 형식이 올바르지 않습니다.
오후 1:43:34  알림  실행이 완료됨

Added LOG record. This action was performed manually and I am not good at coding and all the codes were done using gpt so I do not know the details well. Sorry. If you ask me to solve the problem, I will share the details as much as possible.

7

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.