polynance_sdk
Version:
TypeScript SDK for prediction market aggregation supporting Polymarket, Limitless, and Truemarket
226 lines (225 loc) • 8.49 kB
JavaScript
;
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;
}