@gaberoo/kalshitools 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +666 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/commands/config/init.d.ts +13 -0
- package/dist/commands/config/init.js +89 -0
- package/dist/commands/config/show.d.ts +10 -0
- package/dist/commands/config/show.js +77 -0
- package/dist/commands/markets/list.d.ts +11 -0
- package/dist/commands/markets/list.js +64 -0
- package/dist/commands/markets/show.d.ts +13 -0
- package/dist/commands/markets/show.js +79 -0
- package/dist/commands/orders/cancel.d.ts +14 -0
- package/dist/commands/orders/cancel.js +129 -0
- package/dist/commands/orders/create.d.ts +19 -0
- package/dist/commands/orders/create.js +211 -0
- package/dist/commands/orders/list.d.ts +13 -0
- package/dist/commands/orders/list.js +92 -0
- package/dist/commands/portfolio/balance.d.ts +9 -0
- package/dist/commands/portfolio/balance.js +36 -0
- package/dist/commands/portfolio/fills.d.ts +11 -0
- package/dist/commands/portfolio/fills.js +80 -0
- package/dist/commands/portfolio/positions.d.ts +9 -0
- package/dist/commands/portfolio/positions.js +58 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/base-command.d.ts +13 -0
- package/dist/lib/base-command.js +38 -0
- package/dist/lib/config/manager.d.ts +71 -0
- package/dist/lib/config/manager.js +137 -0
- package/dist/lib/config/schema.d.ts +175 -0
- package/dist/lib/config/schema.js +59 -0
- package/dist/lib/errors/base.d.ts +84 -0
- package/dist/lib/errors/base.js +106 -0
- package/dist/lib/kalshi/auth.d.ts +17 -0
- package/dist/lib/kalshi/auth.js +71 -0
- package/dist/lib/kalshi/client.d.ts +86 -0
- package/dist/lib/kalshi/client.js +228 -0
- package/dist/lib/kalshi/index.d.ts +8 -0
- package/dist/lib/kalshi/index.js +19 -0
- package/dist/lib/kalshi/types.d.ts +155 -0
- package/dist/lib/kalshi/types.js +4 -0
- package/dist/lib/logger.d.ts +9 -0
- package/dist/lib/logger.js +41 -0
- package/dist/lib/output/formatter.d.ts +69 -0
- package/dist/lib/output/formatter.js +111 -0
- package/dist/lib/retry.d.ts +18 -0
- package/dist/lib/retry.js +81 -0
- package/dist/lib/sanitize.d.ts +28 -0
- package/dist/lib/sanitize.js +124 -0
- package/dist/lib/shutdown.d.ts +43 -0
- package/dist/lib/shutdown.js +106 -0
- package/dist/lib/validation.d.ts +37 -0
- package/dist/lib/validation.js +120 -0
- package/oclif.manifest.json +520 -0
- package/package.json +98 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Balance, CreateOrderRequest, Fill, FillsQuery, Market, MarketsQuery, Order, OrderBook, OrdersQuery, Position } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Kalshi API client
|
|
4
|
+
*/
|
|
5
|
+
export declare class KalshiClient {
|
|
6
|
+
private axios;
|
|
7
|
+
private auth;
|
|
8
|
+
private baseUrl;
|
|
9
|
+
constructor(baseUrl: string, keyId: string, privateKey: string);
|
|
10
|
+
/**
|
|
11
|
+
* Make a rate-limited GET request
|
|
12
|
+
*/
|
|
13
|
+
private get;
|
|
14
|
+
/**
|
|
15
|
+
* Make a rate-limited POST request
|
|
16
|
+
*/
|
|
17
|
+
private post;
|
|
18
|
+
/**
|
|
19
|
+
* Make a rate-limited DELETE request
|
|
20
|
+
*/
|
|
21
|
+
private delete;
|
|
22
|
+
/**
|
|
23
|
+
* Get account balance
|
|
24
|
+
*/
|
|
25
|
+
getBalance(): Promise<Balance>;
|
|
26
|
+
/**
|
|
27
|
+
* Get portfolio positions
|
|
28
|
+
*/
|
|
29
|
+
getPositions(params?: {
|
|
30
|
+
ticker?: string;
|
|
31
|
+
settlement_status?: string;
|
|
32
|
+
}): Promise<Position[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Get markets
|
|
35
|
+
*/
|
|
36
|
+
getMarkets(query?: MarketsQuery): Promise<{
|
|
37
|
+
markets: Market[];
|
|
38
|
+
cursor?: string;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Get single market by ticker
|
|
42
|
+
*/
|
|
43
|
+
getMarket(ticker: string): Promise<Market>;
|
|
44
|
+
/**
|
|
45
|
+
* Get order book for a market
|
|
46
|
+
*/
|
|
47
|
+
getOrderBook(ticker: string, depth?: number): Promise<OrderBook>;
|
|
48
|
+
/**
|
|
49
|
+
* Get user orders
|
|
50
|
+
*/
|
|
51
|
+
getOrders(query?: OrdersQuery): Promise<{
|
|
52
|
+
orders: Order[];
|
|
53
|
+
cursor?: string;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Get single order by ID
|
|
57
|
+
*/
|
|
58
|
+
getOrder(orderId: string): Promise<Order>;
|
|
59
|
+
/**
|
|
60
|
+
* Create an order
|
|
61
|
+
*/
|
|
62
|
+
createOrder(request: CreateOrderRequest): Promise<Order>;
|
|
63
|
+
/**
|
|
64
|
+
* Cancel an order
|
|
65
|
+
*/
|
|
66
|
+
cancelOrder(orderId: string): Promise<Order>;
|
|
67
|
+
/**
|
|
68
|
+
* Get fills (executed trades)
|
|
69
|
+
*/
|
|
70
|
+
getFills(query?: FillsQuery): Promise<{
|
|
71
|
+
fills: Fill[];
|
|
72
|
+
cursor?: string;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Test connection to API
|
|
76
|
+
*/
|
|
77
|
+
testConnection(): Promise<boolean>;
|
|
78
|
+
/**
|
|
79
|
+
* Get the base URL
|
|
80
|
+
*/
|
|
81
|
+
getBaseUrl(): string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create a Kalshi client instance
|
|
85
|
+
*/
|
|
86
|
+
export declare function createKalshiClient(baseUrl: string, keyId: string, privateKey: string): KalshiClient;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import Bottleneck from 'bottleneck';
|
|
3
|
+
import { APIError, NetworkError, RateLimitError, TimeoutError } from '../errors/base.js';
|
|
4
|
+
import { logger } from '../logger.js';
|
|
5
|
+
import { KalshiAuth } from './auth.js';
|
|
6
|
+
/**
|
|
7
|
+
* Rate limiter configuration for Kalshi API
|
|
8
|
+
* Basic tier: 20 req/sec for reads, 10 req/sec for writes
|
|
9
|
+
*/
|
|
10
|
+
const READ_LIMITER = new Bottleneck({
|
|
11
|
+
maxConcurrent: 5,
|
|
12
|
+
minTime: 50, // 20 requests per second = 1000ms / 20 = 50ms
|
|
13
|
+
reservoir: 20,
|
|
14
|
+
reservoirRefreshAmount: 20,
|
|
15
|
+
reservoirRefreshInterval: 1000, // Refresh every second
|
|
16
|
+
});
|
|
17
|
+
const WRITE_LIMITER = new Bottleneck({
|
|
18
|
+
maxConcurrent: 3,
|
|
19
|
+
minTime: 100, // 10 requests per second = 1000ms / 10 = 100ms
|
|
20
|
+
reservoir: 10,
|
|
21
|
+
reservoirRefreshAmount: 10,
|
|
22
|
+
reservoirRefreshInterval: 1000,
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Kalshi API client
|
|
26
|
+
*/
|
|
27
|
+
export class KalshiClient {
|
|
28
|
+
axios;
|
|
29
|
+
auth;
|
|
30
|
+
baseUrl;
|
|
31
|
+
constructor(baseUrl, keyId, privateKey) {
|
|
32
|
+
this.baseUrl = baseUrl;
|
|
33
|
+
this.auth = new KalshiAuth(keyId, privateKey);
|
|
34
|
+
this.axios = axios.create({
|
|
35
|
+
baseURL: baseUrl,
|
|
36
|
+
timeout: 30000, // 30 second default timeout
|
|
37
|
+
headers: {
|
|
38
|
+
'Content-Type': 'application/json',
|
|
39
|
+
'Accept': 'application/json',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
// Add request interceptor for authentication
|
|
43
|
+
this.axios.interceptors.request.use((config) => {
|
|
44
|
+
const method = (config.method || 'GET').toUpperCase();
|
|
45
|
+
const path = config.url || '/';
|
|
46
|
+
const authHeaders = this.auth.generateAuthHeaders(method, path);
|
|
47
|
+
// Set auth headers
|
|
48
|
+
for (const [key, value] of Object.entries(authHeaders)) {
|
|
49
|
+
config.headers.set(key, value);
|
|
50
|
+
}
|
|
51
|
+
logger.debug({ method, path }, 'Making API request');
|
|
52
|
+
return config;
|
|
53
|
+
});
|
|
54
|
+
// Add response interceptor for error handling
|
|
55
|
+
this.axios.interceptors.response.use((response) => response, (error) => {
|
|
56
|
+
if (axios.isAxiosError(error)) {
|
|
57
|
+
if (error.code === 'ECONNABORTED') {
|
|
58
|
+
throw new TimeoutError('Request timed out', {
|
|
59
|
+
url: error.config?.url,
|
|
60
|
+
timeout: error.config?.timeout,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (!error.response) {
|
|
64
|
+
throw new NetworkError('Network error - no response received', {
|
|
65
|
+
message: error.message,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const status = error.response.status;
|
|
69
|
+
const data = error.response.data;
|
|
70
|
+
if (status === 429) {
|
|
71
|
+
throw new RateLimitError('Rate limit exceeded', {
|
|
72
|
+
status,
|
|
73
|
+
retryAfter: error.response.headers['retry-after'],
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
throw new APIError(data.error?.message || `API error: ${status}`, {
|
|
77
|
+
status,
|
|
78
|
+
code: data.error?.code,
|
|
79
|
+
details: data.error?.details,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Make a rate-limited GET request
|
|
87
|
+
*/
|
|
88
|
+
async get(path, config) {
|
|
89
|
+
return READ_LIMITER.schedule(async () => {
|
|
90
|
+
const response = await this.axios.get(path, config);
|
|
91
|
+
if (response.data.error) {
|
|
92
|
+
throw new APIError(response.data.error.message, {
|
|
93
|
+
code: response.data.error.code,
|
|
94
|
+
details: response.data.error.details,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return response.data.data;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Make a rate-limited POST request
|
|
102
|
+
*/
|
|
103
|
+
async post(path, data, config) {
|
|
104
|
+
return WRITE_LIMITER.schedule(async () => {
|
|
105
|
+
const response = await this.axios.post(path, data, config);
|
|
106
|
+
if (response.data.error) {
|
|
107
|
+
throw new APIError(response.data.error.message, {
|
|
108
|
+
code: response.data.error.code,
|
|
109
|
+
details: response.data.error.details,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return response.data.data;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Make a rate-limited DELETE request
|
|
117
|
+
*/
|
|
118
|
+
async delete(path, config) {
|
|
119
|
+
return WRITE_LIMITER.schedule(async () => {
|
|
120
|
+
const response = await this.axios.delete(path, config);
|
|
121
|
+
if (response.data.error) {
|
|
122
|
+
throw new APIError(response.data.error.message, {
|
|
123
|
+
code: response.data.error.code,
|
|
124
|
+
details: response.data.error.details,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return response.data.data;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get account balance
|
|
132
|
+
*/
|
|
133
|
+
async getBalance() {
|
|
134
|
+
logger.info('Fetching account balance');
|
|
135
|
+
return this.get('/portfolio/balance');
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get portfolio positions
|
|
139
|
+
*/
|
|
140
|
+
async getPositions(params) {
|
|
141
|
+
logger.info({ params }, 'Fetching portfolio positions');
|
|
142
|
+
return this.get('/portfolio/positions', { params });
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get markets
|
|
146
|
+
*/
|
|
147
|
+
async getMarkets(query) {
|
|
148
|
+
logger.info({ query }, 'Fetching markets');
|
|
149
|
+
return this.get('/markets', { params: query });
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get single market by ticker
|
|
153
|
+
*/
|
|
154
|
+
async getMarket(ticker) {
|
|
155
|
+
logger.info({ ticker }, 'Fetching market details');
|
|
156
|
+
return this.get(`/markets/${ticker}`);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get order book for a market
|
|
160
|
+
*/
|
|
161
|
+
async getOrderBook(ticker, depth) {
|
|
162
|
+
logger.info({ ticker, depth }, 'Fetching order book');
|
|
163
|
+
return this.get(`/markets/${ticker}/orderbook`, {
|
|
164
|
+
params: depth ? { depth } : undefined,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get user orders
|
|
169
|
+
*/
|
|
170
|
+
async getOrders(query) {
|
|
171
|
+
logger.info({ query }, 'Fetching orders');
|
|
172
|
+
return this.get('/portfolio/orders', { params: query });
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get single order by ID
|
|
176
|
+
*/
|
|
177
|
+
async getOrder(orderId) {
|
|
178
|
+
logger.info({ orderId }, 'Fetching order details');
|
|
179
|
+
return this.get(`/portfolio/orders/${orderId}`);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Create an order
|
|
183
|
+
*/
|
|
184
|
+
async createOrder(request) {
|
|
185
|
+
logger.info({ ticker: request.ticker, side: request.side, action: request.action }, 'Creating order');
|
|
186
|
+
return this.post('/portfolio/orders', request);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Cancel an order
|
|
190
|
+
*/
|
|
191
|
+
async cancelOrder(orderId) {
|
|
192
|
+
logger.info({ orderId }, 'Canceling order');
|
|
193
|
+
return this.delete(`/portfolio/orders/${orderId}`);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get fills (executed trades)
|
|
197
|
+
*/
|
|
198
|
+
async getFills(query) {
|
|
199
|
+
logger.info({ query }, 'Fetching fills');
|
|
200
|
+
return this.get('/portfolio/fills', { params: query });
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Test connection to API
|
|
204
|
+
*/
|
|
205
|
+
async testConnection() {
|
|
206
|
+
try {
|
|
207
|
+
await this.getBalance();
|
|
208
|
+
logger.info('API connection test successful');
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
logger.error({ error }, 'API connection test failed');
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Get the base URL
|
|
218
|
+
*/
|
|
219
|
+
getBaseUrl() {
|
|
220
|
+
return this.baseUrl;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Create a Kalshi client instance
|
|
225
|
+
*/
|
|
226
|
+
export function createKalshiClient(baseUrl, keyId, privateKey) {
|
|
227
|
+
return new KalshiClient(baseUrl, keyId, privateKey);
|
|
228
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { KalshiClient } from './client.js';
|
|
2
|
+
export * from './client.js';
|
|
3
|
+
export * from './types.js';
|
|
4
|
+
export * from './auth.js';
|
|
5
|
+
/**
|
|
6
|
+
* Create a Kalshi client from the current configuration
|
|
7
|
+
*/
|
|
8
|
+
export declare function createClientFromConfig(): KalshiClient;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getConfig } from '../config/manager.js';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
import { createKalshiClient } from './client.js';
|
|
4
|
+
export * from './client.js';
|
|
5
|
+
export * from './types.js';
|
|
6
|
+
export * from './auth.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create a Kalshi client from the current configuration
|
|
9
|
+
*/
|
|
10
|
+
export function createClientFromConfig() {
|
|
11
|
+
const configManager = getConfig();
|
|
12
|
+
const apiConfig = configManager.getApiConfig();
|
|
13
|
+
const privateKey = configManager.readPrivateKey();
|
|
14
|
+
logger.info({
|
|
15
|
+
baseUrl: apiConfig.baseUrl,
|
|
16
|
+
environment: configManager.getEnvironment(),
|
|
17
|
+
}, 'Creating Kalshi client from config');
|
|
18
|
+
return createKalshiClient(apiConfig.baseUrl, apiConfig.keyId, privateKey);
|
|
19
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kalshi API types and interfaces
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* API response wrapper
|
|
6
|
+
*/
|
|
7
|
+
export interface KalshiResponse<T> {
|
|
8
|
+
data?: T;
|
|
9
|
+
error?: {
|
|
10
|
+
code: string;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: Record<string, unknown>;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* User balance response
|
|
17
|
+
*/
|
|
18
|
+
export interface Balance {
|
|
19
|
+
balance: number;
|
|
20
|
+
payout: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Market data
|
|
24
|
+
*/
|
|
25
|
+
export interface Market {
|
|
26
|
+
ticker: string;
|
|
27
|
+
event_ticker: string;
|
|
28
|
+
market_type: string;
|
|
29
|
+
title: string;
|
|
30
|
+
subtitle: string;
|
|
31
|
+
open_time: string;
|
|
32
|
+
close_time: string;
|
|
33
|
+
expiration_time: string;
|
|
34
|
+
status: 'active' | 'closed' | 'settled' | 'finalized';
|
|
35
|
+
result?: 'yes' | 'no';
|
|
36
|
+
volume?: number;
|
|
37
|
+
volume_24h?: number;
|
|
38
|
+
liquidity?: number;
|
|
39
|
+
yes_bid?: number;
|
|
40
|
+
yes_ask?: number;
|
|
41
|
+
no_bid?: number;
|
|
42
|
+
no_ask?: number;
|
|
43
|
+
last_price?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Position data
|
|
47
|
+
*/
|
|
48
|
+
export interface Position {
|
|
49
|
+
ticker: string;
|
|
50
|
+
market_ticker: string;
|
|
51
|
+
position: number;
|
|
52
|
+
market_exposure: number;
|
|
53
|
+
total_cost: number;
|
|
54
|
+
fees_paid: number;
|
|
55
|
+
realized_pnl: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Order data
|
|
59
|
+
*/
|
|
60
|
+
export interface Order {
|
|
61
|
+
order_id: string;
|
|
62
|
+
user_id: string;
|
|
63
|
+
ticker: string;
|
|
64
|
+
status: 'pending' | 'resting' | 'canceled' | 'executed' | 'expired';
|
|
65
|
+
yes_price?: number;
|
|
66
|
+
no_price?: number;
|
|
67
|
+
count: number;
|
|
68
|
+
side: 'yes' | 'no';
|
|
69
|
+
action: 'buy' | 'sell';
|
|
70
|
+
type: 'market' | 'limit';
|
|
71
|
+
created_time: string;
|
|
72
|
+
updated_time: string;
|
|
73
|
+
expiration_time?: string;
|
|
74
|
+
remaining_count: number;
|
|
75
|
+
filled_count: number;
|
|
76
|
+
avg_fill_price?: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Fill (executed trade) data
|
|
80
|
+
*/
|
|
81
|
+
export interface Fill {
|
|
82
|
+
fill_id: string;
|
|
83
|
+
order_id: string;
|
|
84
|
+
ticker: string;
|
|
85
|
+
side: 'yes' | 'no';
|
|
86
|
+
action: 'buy' | 'sell';
|
|
87
|
+
count: number;
|
|
88
|
+
price: number;
|
|
89
|
+
created_time: string;
|
|
90
|
+
is_taker: boolean;
|
|
91
|
+
trade_id: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Order book level
|
|
95
|
+
*/
|
|
96
|
+
export interface OrderBookLevel {
|
|
97
|
+
price: number;
|
|
98
|
+
count: number;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Order book data
|
|
102
|
+
*/
|
|
103
|
+
export interface OrderBook {
|
|
104
|
+
ticker: string;
|
|
105
|
+
yes: OrderBookLevel[];
|
|
106
|
+
no: OrderBookLevel[];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create order request
|
|
110
|
+
*/
|
|
111
|
+
export interface CreateOrderRequest {
|
|
112
|
+
ticker: string;
|
|
113
|
+
client_order_id?: string;
|
|
114
|
+
side: 'yes' | 'no';
|
|
115
|
+
action: 'buy' | 'sell';
|
|
116
|
+
count: number;
|
|
117
|
+
type: 'market' | 'limit';
|
|
118
|
+
yes_price?: number;
|
|
119
|
+
no_price?: number;
|
|
120
|
+
expiration_ts?: number;
|
|
121
|
+
sell_position_floor?: number;
|
|
122
|
+
buy_max_cost?: number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Markets query parameters
|
|
126
|
+
*/
|
|
127
|
+
export interface MarketsQuery {
|
|
128
|
+
limit?: number;
|
|
129
|
+
cursor?: string;
|
|
130
|
+
event_ticker?: string;
|
|
131
|
+
series_ticker?: string;
|
|
132
|
+
status?: 'active' | 'closed' | 'settled' | 'finalized';
|
|
133
|
+
tickers?: string;
|
|
134
|
+
with_nested_markets?: boolean;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Orders query parameters
|
|
138
|
+
*/
|
|
139
|
+
export interface OrdersQuery {
|
|
140
|
+
ticker?: string;
|
|
141
|
+
status?: 'pending' | 'resting' | 'canceled' | 'executed' | 'expired';
|
|
142
|
+
limit?: number;
|
|
143
|
+
cursor?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Fills query parameters
|
|
147
|
+
*/
|
|
148
|
+
export interface FillsQuery {
|
|
149
|
+
ticker?: string;
|
|
150
|
+
order_id?: string;
|
|
151
|
+
min_ts?: number;
|
|
152
|
+
max_ts?: number;
|
|
153
|
+
limit?: number;
|
|
154
|
+
cursor?: string;
|
|
155
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
/**
|
|
3
|
+
* Create a logger instance with redaction for sensitive fields
|
|
4
|
+
*/
|
|
5
|
+
export declare function createLogger(options?: {
|
|
6
|
+
level?: string;
|
|
7
|
+
pretty?: boolean;
|
|
8
|
+
}): pino.Logger<never, boolean>;
|
|
9
|
+
export declare const logger: pino.Logger<never, boolean>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
/**
|
|
3
|
+
* Create a logger instance with redaction for sensitive fields
|
|
4
|
+
*/
|
|
5
|
+
export function createLogger(options = {}) {
|
|
6
|
+
const { level = 'info', pretty = false } = options;
|
|
7
|
+
const pinoOptions = {
|
|
8
|
+
level,
|
|
9
|
+
// Redact sensitive fields
|
|
10
|
+
redact: {
|
|
11
|
+
paths: [
|
|
12
|
+
'keyId',
|
|
13
|
+
'privateKey',
|
|
14
|
+
'privateKeyPath',
|
|
15
|
+
'password',
|
|
16
|
+
'token',
|
|
17
|
+
'apiKey',
|
|
18
|
+
'api.*.keyId',
|
|
19
|
+
'api.*.privateKey',
|
|
20
|
+
'api.*.privateKeyPath',
|
|
21
|
+
'*.privateKey',
|
|
22
|
+
'*.password',
|
|
23
|
+
'*.token',
|
|
24
|
+
],
|
|
25
|
+
censor: '[REDACTED]',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
if (pretty) {
|
|
29
|
+
return pino(pinoOptions, pino.transport({
|
|
30
|
+
target: 'pino-pretty',
|
|
31
|
+
options: {
|
|
32
|
+
colorize: true,
|
|
33
|
+
translateTime: 'HH:MM:ss',
|
|
34
|
+
ignore: 'pid,hostname',
|
|
35
|
+
},
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
return pino(pinoOptions);
|
|
39
|
+
}
|
|
40
|
+
// Default logger instance
|
|
41
|
+
export const logger = createLogger({ level: process.env.LOG_LEVEL || 'info', pretty: true });
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import Table from 'cli-table3';
|
|
2
|
+
/**
|
|
3
|
+
* Standard success response structure
|
|
4
|
+
*/
|
|
5
|
+
export interface SuccessResponse<T = unknown> {
|
|
6
|
+
success: true;
|
|
7
|
+
data: T;
|
|
8
|
+
metadata: {
|
|
9
|
+
timestamp: string;
|
|
10
|
+
command?: string;
|
|
11
|
+
duration_ms?: number;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Standard error response structure
|
|
16
|
+
*/
|
|
17
|
+
export interface ErrorResponse {
|
|
18
|
+
success: false;
|
|
19
|
+
error: {
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
22
|
+
details?: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
metadata: {
|
|
25
|
+
timestamp: string;
|
|
26
|
+
command?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Output formatter for both human and JSON formats
|
|
31
|
+
*/
|
|
32
|
+
export declare class OutputFormatter {
|
|
33
|
+
private jsonMode;
|
|
34
|
+
private startTime;
|
|
35
|
+
private command?;
|
|
36
|
+
constructor(jsonMode?: boolean, command?: string);
|
|
37
|
+
/**
|
|
38
|
+
* Output a success response
|
|
39
|
+
*/
|
|
40
|
+
success<T>(data: T): void;
|
|
41
|
+
/**
|
|
42
|
+
* Output an error response
|
|
43
|
+
*/
|
|
44
|
+
error(code: string, message: string, details?: Record<string, unknown>): void;
|
|
45
|
+
/**
|
|
46
|
+
* Create a table for human-readable output
|
|
47
|
+
*/
|
|
48
|
+
createTable(head: string[], rows: string[][]): Table.Table;
|
|
49
|
+
/**
|
|
50
|
+
* Output a table
|
|
51
|
+
*/
|
|
52
|
+
outputTable(head: string[], rows: string[][]): void;
|
|
53
|
+
/**
|
|
54
|
+
* Create a success response object
|
|
55
|
+
*/
|
|
56
|
+
createSuccessResponse<T>(data: T): SuccessResponse<T>;
|
|
57
|
+
/**
|
|
58
|
+
* Create an error response object
|
|
59
|
+
*/
|
|
60
|
+
createErrorResponse(code: string, message: string, details?: Record<string, unknown>): ErrorResponse;
|
|
61
|
+
/**
|
|
62
|
+
* Output JSON to stdout
|
|
63
|
+
*/
|
|
64
|
+
private outputJSON;
|
|
65
|
+
/**
|
|
66
|
+
* Check if JSON mode is enabled
|
|
67
|
+
*/
|
|
68
|
+
isJSONMode(): boolean;
|
|
69
|
+
}
|