| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- import axios from "axios";
- import qs from "qs";
- import { HttpsProxyAgent } from "https-proxy-agent";
- import { ClobClient, Side, OrderType } from "@polymarket/clob-client";
- import { Wallet } from "ethers";
- import WebSocketClient from "./WebSocketClient.js";
- import Logs from "./logs.js";
- /**
- * axios 默认配置
- */
- const axiosDefaultOptions = {
- baseURL: "",
- url: "",
- method: "GET",
- headers: {},
- params: {},
- data: {},
- timeout: 10000,
- };
- /**
- * 通用请求
- * @param {*} options
- * @param {*} baseURL
- * @returns
- */
- const clientRequest = async (options, baseURL) => {
- const { url } = options;
- if (!url || !baseURL) {
- throw new Error("url and baseURL are required");
- }
- const mergedOptions = {
- ...axiosDefaultOptions,
- ...options,
- baseURL,
- paramsSerializer: params => qs.stringify(params, { arrayFormat: 'repeat' })
- };
- const proxy = process.env.NODE_HTTP_PROXY;
- if (proxy) {
- mergedOptions.proxy = false;
- mergedOptions.httpsAgent = new HttpsProxyAgent(proxy);
- }
- return axios(mergedOptions).then(res => res.data);
- }
- /**
- * 请求市场数据
- * @param {*} options
- * @returns
- */
- const requestMarketData = async (options) => {
- return clientRequest(options, "https://gamma-api.polymarket.com");
- }
- /**
- * 请求订单簿数据
- */
- const requestClobData = async (options) => {
- return clientRequest(options, "https://clob.polymarket.com");
- }
- /**
- * 获取足球联赛
- * @returns {Promise}
- */
- export const getSoccerSports = async () => {
- return requestMarketData({ url: "/sports" })
- .then(sportsData => {
- return sportsData.filter(item => {
- const { tags } = item;
- const tagIds = tags.split(",").map(item => +item);
- return tagIds.includes(100350);
- });
- });
- }
- /**
- * 获取赛事数据
- * @param {Object} options
- * @param {number} options.limit
- * @param {number} options.tag_id
- * @param {boolean} options.active
- * @param {boolean} options.closed
- * @param {string} options.endDateMin
- * @param {string} options.endDateMax
- * @returns {Promise}
- */
- export const getEvents = async ({
- limit = 500, tag_id = 100350, active = true,
- closed = false, endDateMin = "", endDateMax = "",
- } = {}) => {
- return requestMarketData({
- url: "/events",
- params: {
- limit, tag_id, active, closed,
- end_date_min: endDateMin,
- end_date_max: endDateMax,
- }
- }).then(events => events.filter(item => !!item.series));
- }
- /**
- * 获取订单簿数据
- */
- export const getOrderBook = async (tokenId) => {
- return requestClobData({
- url: "/book",
- params: {
- token_id: tokenId,
- }
- });
- }
- /**
- * 批量获取订单簿数据
- * @param {Array} tokenIds
- * @returns {Promise}
- */
- export const getMultipleOrderBooks = async (tokenIds) => {
- return requestClobData({
- url: "/books",
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- data: tokenIds.map(tokenId => ({ token_id: tokenId })),
- });
- }
- /**
- * 下注
- */
- export const placeOrder = async (info) => {
- // return Promise.resolve(info);
- const { asset_id, bestPrice, stakeSize, tick_size: tickSize, neg_risk: negRisk } = info;
- const HOST = "https://clob.polymarket.com";
- const CHAIN_ID = 137; // Polygon mainnet
- const signer = new Wallet(process.env.POLYMARKET_PRIVATE_KEY);
- const userApiCreds = {
- key: process.env.POLYMARKET_API_KEY,
- secret: process.env.POLYMARKET_API_SECRET,
- passphrase: process.env.POLYMARKET_API_PASSPHRASE,
- };
- const SIGNATURE_TYPE = 0;
- const FUNDER_ADDRESS = signer.address;
- // Logs.outDev('clob client init', HOST, CHAIN_ID, signer.address, userApiCreds, SIGNATURE_TYPE, FUNDER_ADDRESS);
- const client = new ClobClient(
- HOST,
- CHAIN_ID,
- signer,
- userApiCreds,
- SIGNATURE_TYPE,
- FUNDER_ADDRESS
- );
- const orderData = {
- tokenID: asset_id,
- price: bestPrice,
- size: stakeSize,
- side: Side.BUY,
- }
- const orderOptions = { tickSize, negRisk }
- Logs.outDev('polymarket place order data', orderData, orderOptions, OrderType.FOK);
- // return client.getBalanceAllowance({ asset_type: 'COLLATERAL' })
- return client.createAndPostOrder(orderData, orderOptions, OrderType.FOK)
- .then(res => {
- // if (res.error) {
- // return Promise.reject(new Error(res.error));
- // }
- return res;
- });
- // return Promise.resolve(info);
- // return Promise.reject(new Error('polymarket place order not implemented', { cause: 400 }));
- }
- /**
- * 请求平台数据
- * @param {*} options
- * @returns {Promise}
- */
- export const platformRequest = async (options) => {
- const { url } = options;
- if (!url) {
- throw new Error("url is required");
- }
- const mergedOptions = {
- ...axiosDefaultOptions,
- ...options,
- baseURL: "http://127.0.0.1:9020",
- };
- return axios(mergedOptions).then(res => res.data);
- }
- /**
- * 请求平台 POST 数据
- * @param {string} url
- * @param {Object} data
- * @returns {Promise}
- */
- export const platformPost = async (url, data) => {
- return platformRequest({
- url,
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- data,
- });
- }
- /**
- * 请求平台 GET 数据
- * @param {string} url
- * @param {Object} params
- * @returns {Promise}
- */
- export const platformGet = async (url, params) => {
- return platformRequest({ url, method: 'GET', params });
- }
- /**
- * 市场 WebSocket 客户端
- */
- export class MarketWsClient extends WebSocketClient {
- #assetIds = [];
- constructor() {
- let agent;
- const proxy = process.env.NODE_HTTP_PROXY;
- if (proxy) {
- agent = new HttpsProxyAgent(proxy);
- }
- super("wss://ws-subscriptions-clob.polymarket.com/ws/market", { agent });
- }
- connect() {
- super.connect();
- this.on('open', () => {
- if (this.#assetIds.length > 0) {
- this.subscribeToTokensIds(this.#assetIds);
- }
- });
- }
- subscribeToTokensIds(assetIds) {
- this.#assetIds = [...new Set([...this.#assetIds, ...assetIds])];
- this.send({
- operation: "subscribe",
- assets_ids: assetIds,
- });
- }
- unsubscribeToTokensIds(assetIds) {
- const assetIdsSet = new Set(assetIds);
- this.#assetIds = this.#assetIds.filter(id => !assetIdsSet.has(id));
- this.send({
- operation: "unsubscribe",
- assets_ids: assetIds,
- });
- }
- }
|