UNPKG

polynance_sdk

Version:

TypeScript SDK for prediction market aggregation supporting Polymarket, Limitless, and Truemarket

226 lines (225 loc) 8.49 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PolynanceClient = void 0; exports.generateCandlestickData = generateCandlestickData; const axios_1 = __importDefault(require("axios")); /** * 予測市場のアグリゲータクライアント */ class PolynanceClient { constructor(options) { const apiBaseUrl = options?.apiBaseUrl || 'http://57.180.216.102:9000'; this.sseBaseUrl = options?.sseBaseUrl || 'http://57.180.216.102:9000'; this.apiClient = axios_1.default.create({ baseURL: apiBaseUrl, timeout: 100000, headers: { 'Content-Type': 'application/json', }, }); } /** * 指定されたプロトコルとイベントIDに対応するイベント情報を取得 */ async getEvent(protocol, eventId) { try { const response = await this.apiClient.get(`/v1/events/${eventId}`, { params: { protocol }, }); return response.data; } catch (error) { this.handleError('getEvent', error); throw error; } } /** * 指定されたプロトコルとマーケットIDに対応するマーケット情報を取得 */ async getMarket(protocol, marketId) { try { const response = await this.apiClient.get(`/v1/markets/${marketId}`, { params: { protocol }, }); return response.data; } catch (error) { this.handleError('getMarket', error); throw error; } } /** * 指定されたプロトコルの進行中のイベント一覧を取得 */ async getOngoingEvents(protocol, page = 1, limit = 50) { try { const response = await this.apiClient.get('/v1/ongoing-events', { params: { protocol, page, limit }, }); return response.data; } catch (error) { this.handleError('getOngoingEvents', error); throw error; } } /** * 指定されたプロトコルとイベントIDに対応するコメント一覧を取得 */ async getEventComments(protocol, eventId) { try { const response = await this.apiClient.get(`/v1/events/${eventId}/comments`, { params: { protocol }, }); return response.data; } catch (error) { this.handleError('getEventComments', error); throw error; } } /** * 指定されたプロトコルとマーケットIDに対応するオーダーブック情報を取得 */ async getOrderbook(protocol, marketId) { try { const response = await this.apiClient.get(`/v1/markets/${marketId}/orderbook`, { params: { protocol }, }); return response.data; } catch (error) { this.handleError('getOrderbook', error); throw error; } } /** * Retrieves the filled order events for position tokens in a market for the last month. * Returns price and timestamp data for each execution in the orderbook. * * The response is a 2D array where the index corresponds to the position tokens * in the same order as they appear in the market response's position_tokens array. * For binary options, index 0 corresponds to "Yes" tokens. * * @param protocol - The protocol identifier * @param marketId - The market identifier * @returns A 2D array of fill event data, organized by position token index */ async getOrderBookFilledEvents(protocol, marketId) { try { const response = await this.apiClient.get(`/v1/markets/${marketId}/orderbook/filledevents`, { params: { protocol }, }); return response.data; } catch (error) { this.handleError('getOrderBookFilledEvents', error); throw error; } } /** * 指定されたプロトコルと ID(マーケットID等) に対応する Fill イベントを SSE で購読 * * @param protocol プロトコル名 * @param id マーケットID等 * @param handlers SSE購読時の各種コールバック (onOpen, onMessage, onError) * @returns SSE購読インスタンス (eventSource, close, getLatestData) */ subscribeFillEvents(protocol, id, handlers) { const url = `${this.sseBaseUrl}/sse/fillevent?protocol=${protocol}&id=${id}`; const eventSource = new EventSource(url); let latestData = null; // SSE接続が開いたとき eventSource.onopen = (ev) => { if (handlers?.onOpen) { handlers.onOpen(ev); } }; // メッセージを受信したとき eventSource.onmessage = (event) => { try { const data = JSON.parse(event.data); latestData = data; // 最新データを更新 if (handlers?.onMessage) { handlers.onMessage(data); } } catch (error) { console.error('Error parsing SSE message:', error); } }; // エラーが発生したとき eventSource.onerror = (ev) => { if (handlers?.onError) { handlers.onError(ev); } else { console.error('SSE connection error:', ev); } }; const close = () => { eventSource.close(); }; return { eventSource, close, getLatestData: () => latestData, }; } /** * エラーハンドリング */ handleError(method, error) { if (axios_1.default.isAxiosError(error)) { console.error(`PolynanceClient.${method} error:`, error.response?.data || error.message); } else { console.error(`PolynanceClient.${method} error:`, error); } } } exports.PolynanceClient = PolynanceClient; function generateCandlestickData(fillEvents, intervalMillis, fromTime, toTime) { // タイムスタンプを秒からミリ秒に変換する const convertedEvents = fillEvents.map(event => ({ ...event, timestamp: event.timestamp * 1000 // 秒からミリ秒へ変換 })); // 指定期間内の FillEventData のみに絞る const filteredEvents = convertedEvents.filter((event) => event.timestamp >= fromTime && event.timestamp < toTime); // タイムスタンプの昇順にソート filteredEvents.sort((a, b) => a.timestamp - b.timestamp); // timeBucket(ローソク足の開始時刻)毎のローソク足データを保持するマップ const candleMap = new Map(); for (const event of filteredEvents) { // どのローソク足に属するか (interval の開始時刻) を計算 const bucketTimeMillis = Math.floor(event.timestamp / intervalMillis) * intervalMillis; // すでにローソク足データがあるかチェック const existingCandle = candleMap.get(bucketTimeMillis); if (!existingCandle) { // 新しくローソク足を作成 candleMap.set(bucketTimeMillis, { // TradingView が秒単位を想定している場合、ミリ秒→秒に変換しておく time: Math.floor(bucketTimeMillis / 1000), open: event.price, high: event.price, low: event.price, close: event.price, volume: event.volumeBase, }); } else { // 既存のローソク足を更新 existingCandle.high = Math.max(existingCandle.high, event.price); existingCandle.low = Math.min(existingCandle.low, event.price); existingCandle.close = event.price; existingCandle.volume += event.volumeBase; } } // Map を配列に変換し、time (秒) 昇順にソートして返却 const candles = Array.from(candleMap.values()).sort((a, b) => a.time - b.time); return candles; }