@gaberoo/kalshitools 1.0.2 → 1.1.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 +328 -27
- package/dist/commands/config/init.js +4 -4
- package/dist/commands/config/show.js +5 -5
- package/dist/commands/markets/list.d.ts +5 -1
- package/dist/commands/markets/list.js +28 -8
- package/dist/commands/markets/orderbook.d.ts +13 -0
- package/dist/commands/markets/orderbook.js +83 -0
- package/dist/commands/markets/scan.d.ts +18 -0
- package/dist/commands/markets/scan.js +237 -0
- package/dist/commands/markets/show.d.ts +3 -3
- package/dist/commands/markets/show.js +7 -7
- package/dist/commands/orders/cancel.d.ts +3 -3
- package/dist/commands/orders/cancel.js +7 -7
- package/dist/commands/orders/create.d.ts +5 -5
- package/dist/commands/orders/create.js +33 -33
- package/dist/commands/orders/list.d.ts +1 -1
- package/dist/commands/orders/list.js +9 -9
- package/dist/commands/portfolio/analytics.d.ts +12 -0
- package/dist/commands/portfolio/analytics.js +192 -0
- package/dist/commands/portfolio/fills.d.ts +1 -1
- package/dist/commands/portfolio/fills.js +7 -7
- package/dist/commands/portfolio/history.d.ts +14 -0
- package/dist/commands/portfolio/history.js +245 -0
- package/dist/commands/portfolio/positions.d.ts +1 -0
- package/dist/commands/portfolio/positions.js +11 -2
- package/dist/commands/portfolio/risk.d.ts +11 -0
- package/dist/commands/portfolio/risk.js +206 -0
- package/dist/lib/analytics.d.ts +64 -0
- package/dist/lib/analytics.js +236 -0
- package/dist/lib/base-command.d.ts +2 -2
- package/dist/lib/base-command.js +8 -8
- package/dist/lib/config/manager.d.ts +25 -25
- package/dist/lib/config/manager.js +51 -51
- package/dist/lib/config/schema.d.ts +11 -11
- package/dist/lib/config/schema.js +6 -6
- package/dist/lib/errors/base.d.ts +10 -10
- package/dist/lib/errors/base.js +7 -7
- package/dist/lib/kalshi/auth.d.ts +4 -4
- package/dist/lib/kalshi/auth.js +24 -24
- package/dist/lib/kalshi/client.d.ts +35 -35
- package/dist/lib/kalshi/client.js +93 -91
- package/dist/lib/kalshi/index.d.ts +1 -1
- package/dist/lib/kalshi/index.js +1 -1
- package/dist/lib/kalshi/types.d.ts +53 -53
- package/dist/lib/logger.js +3 -3
- package/dist/lib/output/formatter.d.ts +20 -20
- package/dist/lib/output/formatter.js +55 -55
- package/dist/lib/retry.d.ts +2 -2
- package/dist/lib/retry.js +8 -10
- package/dist/lib/risk.d.ts +51 -0
- package/dist/lib/risk.js +153 -0
- package/dist/lib/sanitize.js +9 -9
- package/dist/lib/scanner.d.ts +58 -0
- package/dist/lib/scanner.js +160 -0
- package/dist/lib/shutdown.d.ts +4 -4
- package/dist/lib/shutdown.js +7 -7
- package/dist/lib/validation.d.ts +5 -5
- package/dist/lib/validation.js +14 -20
- package/docs/TRADING_STRATEGIES.md +538 -0
- package/oclif.manifest.json +559 -170
- package/package.json +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../lib/base-command.js';
|
|
2
|
+
export default class MarketsOrderbook extends BaseCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
ticker: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
depth: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { BaseCommand } from '../../lib/base-command.js';
|
|
4
|
+
import { createClientFromConfig } from '../../lib/kalshi/index.js';
|
|
5
|
+
import { logger } from '../../lib/logger.js';
|
|
6
|
+
export default class MarketsOrderbook extends BaseCommand {
|
|
7
|
+
static args = {
|
|
8
|
+
ticker: Args.string({
|
|
9
|
+
description: 'Market ticker symbol',
|
|
10
|
+
required: true,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static description = 'Show order book for a market';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %> TICKER',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> TICKER --depth 5',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> TICKER --json',
|
|
18
|
+
];
|
|
19
|
+
static flags = {
|
|
20
|
+
...BaseCommand.baseFlags,
|
|
21
|
+
depth: Flags.integer({
|
|
22
|
+
default: 10,
|
|
23
|
+
description: 'Number of price levels to show',
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
const { args, flags } = await this.parse(MarketsOrderbook);
|
|
28
|
+
try {
|
|
29
|
+
// Create API client from configuration
|
|
30
|
+
const client = createClientFromConfig();
|
|
31
|
+
// Fetch order book
|
|
32
|
+
const orderbook = await client.getOrderBook(args.ticker, flags.depth);
|
|
33
|
+
if (this.formatter.isJSONMode()) {
|
|
34
|
+
this.formatter.success(orderbook);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Human-readable output
|
|
38
|
+
this.log(chalk.cyan.bold(`Order Book: ${orderbook.ticker}`));
|
|
39
|
+
this.log();
|
|
40
|
+
// YES Side (Buy)
|
|
41
|
+
this.log(chalk.green.bold('YES Side (Buy)'));
|
|
42
|
+
if (orderbook.yes.length === 0) {
|
|
43
|
+
this.log(chalk.gray(' No orders'));
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const yesRows = orderbook.yes.map((level) => [
|
|
47
|
+
level.price.toFixed(2),
|
|
48
|
+
level.count.toString(),
|
|
49
|
+
(level.price * level.count).toFixed(2),
|
|
50
|
+
]);
|
|
51
|
+
this.formatter.outputTable(['Price', 'Quantity', 'Total'], yesRows);
|
|
52
|
+
}
|
|
53
|
+
this.log();
|
|
54
|
+
// NO Side (Sell)
|
|
55
|
+
this.log(chalk.red.bold('NO Side (Sell)'));
|
|
56
|
+
if (orderbook.no.length === 0) {
|
|
57
|
+
this.log(chalk.gray(' No orders'));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const noRows = orderbook.no.map((level) => [
|
|
61
|
+
level.price.toFixed(2),
|
|
62
|
+
level.count.toString(),
|
|
63
|
+
(level.price * level.count).toFixed(2),
|
|
64
|
+
]);
|
|
65
|
+
this.formatter.outputTable(['Price', 'Quantity', 'Total'], noRows);
|
|
66
|
+
}
|
|
67
|
+
// Calculate and display spread if both sides have orders
|
|
68
|
+
if (orderbook.yes.length > 0 && orderbook.no.length > 0) {
|
|
69
|
+
const bestYes = orderbook.yes[0].price;
|
|
70
|
+
const bestNo = orderbook.no[0].price;
|
|
71
|
+
const spread = Math.abs(bestYes - bestNo);
|
|
72
|
+
const spreadPct = ((spread / ((bestYes + bestNo) / 2)) * 100).toFixed(1);
|
|
73
|
+
this.log();
|
|
74
|
+
this.log(`${chalk.cyan('Spread:')} ${spread.toFixed(2)} (${spreadPct}%)`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
logger.info({ depth: flags.depth, ticker: args.ticker }, 'Order book fetched successfully');
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BaseCommand } from '../../lib/base-command.js';
|
|
2
|
+
export default class MarketsScan extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
depth: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'event-ticker': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'max-spread': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'min-liquidity': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'min-spread': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
'min-volume': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
'series-ticker': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
'sort-by': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
};
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { BaseCommand } from '../../lib/base-command.js';
|
|
4
|
+
import { createClientFromConfig } from '../../lib/kalshi/index.js';
|
|
5
|
+
import { logger } from '../../lib/logger.js';
|
|
6
|
+
import { calculateOrderbookLiquidity, calculateSpread, classifyOpportunity, filterMarketsByCriteria, generateOpportunityReason, scoreMarket, } from '../../lib/scanner.js';
|
|
7
|
+
export default class MarketsScan extends BaseCommand {
|
|
8
|
+
static description = 'Scan markets for trading opportunities based on liquidity and spreads';
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> <%= command.id %>',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> --min-liquidity 200 --min-spread 0.05',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --event-ticker EVENT-2024',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> --sort-by liquidity --limit 20',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
...BaseCommand.baseFlags,
|
|
18
|
+
'depth': Flags.integer({
|
|
19
|
+
default: 5,
|
|
20
|
+
description: 'Orderbook depth to fetch for analysis',
|
|
21
|
+
}),
|
|
22
|
+
'event-ticker': Flags.string({
|
|
23
|
+
description: 'Filter to specific event',
|
|
24
|
+
}),
|
|
25
|
+
'limit': Flags.integer({
|
|
26
|
+
default: 50,
|
|
27
|
+
description: 'Maximum markets to scan',
|
|
28
|
+
}),
|
|
29
|
+
'max-spread': Flags.string({
|
|
30
|
+
default: '0.30',
|
|
31
|
+
description: 'Maximum spread in cents (e.g., 0.30 = 30 cents)',
|
|
32
|
+
}),
|
|
33
|
+
'min-liquidity': Flags.string({
|
|
34
|
+
default: '100',
|
|
35
|
+
description: 'Minimum orderbook depth in dollars',
|
|
36
|
+
}),
|
|
37
|
+
'min-spread': Flags.string({
|
|
38
|
+
default: '0.03',
|
|
39
|
+
description: 'Minimum spread in cents (e.g., 0.03 = 3 cents)',
|
|
40
|
+
}),
|
|
41
|
+
'min-volume': Flags.string({
|
|
42
|
+
default: '500',
|
|
43
|
+
description: 'Minimum 24h volume in dollars',
|
|
44
|
+
}),
|
|
45
|
+
'series-ticker': Flags.string({
|
|
46
|
+
description: 'Filter to specific series',
|
|
47
|
+
}),
|
|
48
|
+
'sort-by': Flags.string({
|
|
49
|
+
default: 'score',
|
|
50
|
+
description: 'Ranking criteria',
|
|
51
|
+
options: ['liquidity', 'score', 'spread', 'volume'],
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
async run() {
|
|
55
|
+
const { flags } = await this.parse(MarketsScan);
|
|
56
|
+
try {
|
|
57
|
+
const client = createClientFromConfig();
|
|
58
|
+
// Parse numeric flags
|
|
59
|
+
const minLiquidity = Number.parseFloat(flags['min-liquidity']);
|
|
60
|
+
const minSpread = Number.parseFloat(flags['min-spread']);
|
|
61
|
+
const maxSpread = Number.parseFloat(flags['max-spread']);
|
|
62
|
+
const minVolume = Number.parseFloat(flags['min-volume']);
|
|
63
|
+
if (!this.formatter.isJSONMode()) {
|
|
64
|
+
this.log(chalk.cyan.bold('Scanning Markets for Opportunities...'));
|
|
65
|
+
this.log();
|
|
66
|
+
}
|
|
67
|
+
// Fetch active markets
|
|
68
|
+
const marketsResult = await client.getMarkets({
|
|
69
|
+
event_ticker: flags['event-ticker'],
|
|
70
|
+
limit: flags.limit,
|
|
71
|
+
series_ticker: flags['series-ticker'],
|
|
72
|
+
status: 'active',
|
|
73
|
+
});
|
|
74
|
+
const { markets } = marketsResult;
|
|
75
|
+
if (markets.length === 0) {
|
|
76
|
+
if (this.formatter.isJSONMode()) {
|
|
77
|
+
this.formatter.success({
|
|
78
|
+
markets: [],
|
|
79
|
+
opportunities: 0,
|
|
80
|
+
scanned: 0,
|
|
81
|
+
stats: {
|
|
82
|
+
avg_liquidity: 0,
|
|
83
|
+
avg_spread: 0,
|
|
84
|
+
avg_volume_24h: 0,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this.log(chalk.yellow('No active markets found'));
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (!this.formatter.isJSONMode()) {
|
|
94
|
+
this.log(`Found ${markets.length} active markets. Fetching orderbooks...`);
|
|
95
|
+
this.log(chalk.gray('(This may take a few seconds due to rate limiting)'));
|
|
96
|
+
this.log();
|
|
97
|
+
}
|
|
98
|
+
// Fetch orderbooks for all markets (rate limited automatically by client)
|
|
99
|
+
const marketData = [];
|
|
100
|
+
for (const market of markets) {
|
|
101
|
+
try {
|
|
102
|
+
const orderbook = await client.getOrderBook(market.ticker, flags.depth);
|
|
103
|
+
const liquidity = calculateOrderbookLiquidity(orderbook);
|
|
104
|
+
const spreadData = calculateSpread(orderbook);
|
|
105
|
+
const volume = market.volume_24h || market.volume || 0;
|
|
106
|
+
const score = scoreMarket(market, orderbook);
|
|
107
|
+
marketData.push({
|
|
108
|
+
liquidity: liquidity.total,
|
|
109
|
+
market,
|
|
110
|
+
orderbook,
|
|
111
|
+
score,
|
|
112
|
+
spread: spreadData ? spreadData.spreadCents : null,
|
|
113
|
+
volume,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
logger.debug({ error, ticker: market.ticker }, 'Failed to fetch orderbook');
|
|
118
|
+
// Skip markets with orderbook fetch errors
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Filter markets by criteria
|
|
123
|
+
const filtered = filterMarketsByCriteria(marketData, {
|
|
124
|
+
maxSpread,
|
|
125
|
+
minLiquidity,
|
|
126
|
+
minSpread,
|
|
127
|
+
minVolume,
|
|
128
|
+
});
|
|
129
|
+
// Sort markets
|
|
130
|
+
const sorted = [...filtered];
|
|
131
|
+
if (flags['sort-by'] === 'liquidity') {
|
|
132
|
+
sorted.sort((a, b) => b.liquidity - a.liquidity);
|
|
133
|
+
}
|
|
134
|
+
else if (flags['sort-by'] === 'spread') {
|
|
135
|
+
sorted.sort((a, b) => (b.spread || 0) - (a.spread || 0));
|
|
136
|
+
}
|
|
137
|
+
else if (flags['sort-by'] === 'volume') {
|
|
138
|
+
sorted.sort((a, b) => b.volume - a.volume);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Default to score
|
|
142
|
+
sorted.sort((a, b) => b.score - a.score);
|
|
143
|
+
}
|
|
144
|
+
// Calculate statistics
|
|
145
|
+
const avgLiquidity = filtered.length > 0
|
|
146
|
+
? filtered.reduce((sum, m) => sum + m.liquidity, 0) / filtered.length
|
|
147
|
+
: 0;
|
|
148
|
+
const avgSpread = filtered.length > 0
|
|
149
|
+
? filtered.filter(m => m.spread !== null).reduce((sum, m) => sum + (m.spread || 0), 0) / filtered.filter(m => m.spread !== null).length
|
|
150
|
+
: 0;
|
|
151
|
+
const avgVolume24h = filtered.length > 0
|
|
152
|
+
? filtered.reduce((sum, m) => sum + m.volume, 0) / filtered.length
|
|
153
|
+
: 0;
|
|
154
|
+
if (this.formatter.isJSONMode()) {
|
|
155
|
+
const opportunities = sorted.map(m => {
|
|
156
|
+
const spreadData = m.orderbook ? calculateSpread(m.orderbook) : null;
|
|
157
|
+
const liquidityData = m.orderbook ? calculateOrderbookLiquidity(m.orderbook) : { noTotal: 0, total: 0, yesTotal: 0 };
|
|
158
|
+
const opportunityType = classifyOpportunity(m.spread || 0, m.liquidity, m.volume);
|
|
159
|
+
return {
|
|
160
|
+
liquidity: {
|
|
161
|
+
no_total: liquidityData.noTotal,
|
|
162
|
+
total: liquidityData.total,
|
|
163
|
+
yes_total: liquidityData.yesTotal,
|
|
164
|
+
},
|
|
165
|
+
opportunity_type: opportunityType,
|
|
166
|
+
reason: generateOpportunityReason(opportunityType, m.spread || 0, m.liquidity, m.volume),
|
|
167
|
+
score: m.score,
|
|
168
|
+
spread: spreadData ? {
|
|
169
|
+
spread_cents: spreadData.spreadCents,
|
|
170
|
+
spread_pct: spreadData.spreadPct,
|
|
171
|
+
yes_ask: spreadData.yesAsk,
|
|
172
|
+
yes_bid: spreadData.yesBid,
|
|
173
|
+
} : null,
|
|
174
|
+
ticker: m.market.ticker,
|
|
175
|
+
title: m.market.title,
|
|
176
|
+
volume: {
|
|
177
|
+
volume_24h: m.volume,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
this.formatter.success({
|
|
182
|
+
markets: opportunities,
|
|
183
|
+
opportunities: filtered.length,
|
|
184
|
+
scanned: markets.length,
|
|
185
|
+
stats: {
|
|
186
|
+
avg_liquidity: avgLiquidity,
|
|
187
|
+
avg_spread: avgSpread,
|
|
188
|
+
avg_volume_24h: avgVolume24h,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
// Human-readable output
|
|
194
|
+
this.log(chalk.cyan.bold('Market Opportunities'));
|
|
195
|
+
this.log();
|
|
196
|
+
this.log(chalk.yellow('Summary:'));
|
|
197
|
+
this.log(` Markets Scanned: ${markets.length}`);
|
|
198
|
+
this.log(` Opportunities Found: ${filtered.length}`);
|
|
199
|
+
this.log(` Avg Liquidity: ${chalk.cyan('$' + avgLiquidity.toFixed(2))}`);
|
|
200
|
+
this.log(` Avg Spread: ${chalk.cyan(avgSpread.toFixed(3))} cents`);
|
|
201
|
+
this.log(` Avg 24h Volume: ${chalk.cyan('$' + avgVolume24h.toFixed(2))}`);
|
|
202
|
+
this.log();
|
|
203
|
+
if (sorted.length > 0) {
|
|
204
|
+
this.log(chalk.yellow('Top Opportunities:'));
|
|
205
|
+
const rows = sorted.slice(0, 20).map(m => {
|
|
206
|
+
const spreadData = m.orderbook ? calculateSpread(m.orderbook) : null;
|
|
207
|
+
return [
|
|
208
|
+
m.market.ticker,
|
|
209
|
+
m.score.toString(),
|
|
210
|
+
spreadData ? spreadData.spreadCents.toFixed(3) : 'N/A',
|
|
211
|
+
'$' + m.liquidity.toFixed(0),
|
|
212
|
+
'$' + m.volume.toFixed(0),
|
|
213
|
+
m.market.title.length > 40 ? m.market.title.slice(0, 37) + '...' : m.market.title,
|
|
214
|
+
];
|
|
215
|
+
});
|
|
216
|
+
this.formatter.outputTable(['Ticker', 'Score', 'Spread', 'Liquidity', '24h Vol', 'Title'], rows);
|
|
217
|
+
if (sorted.length > 20) {
|
|
218
|
+
this.log();
|
|
219
|
+
this.log(chalk.gray(` ... showing top 20 of ${sorted.length} opportunities`));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
this.log(chalk.yellow('No opportunities found matching criteria'));
|
|
224
|
+
}
|
|
225
|
+
this.log();
|
|
226
|
+
this.log(chalk.gray('Tip: Use --json for full data including orderbook details'));
|
|
227
|
+
}
|
|
228
|
+
logger.info({
|
|
229
|
+
filtered: filtered.length,
|
|
230
|
+
scanned: markets.length,
|
|
231
|
+
}, 'Market scan completed');
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { BaseCommand } from '../../lib/base-command.js';
|
|
2
2
|
export default class MarketsShow extends BaseCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
ticker: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
3
6
|
static description: string;
|
|
4
7
|
static examples: string[];
|
|
5
8
|
static flags: {
|
|
6
9
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
10
|
};
|
|
8
|
-
static args: {
|
|
9
|
-
ticker: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
10
|
-
};
|
|
11
11
|
run(): Promise<void>;
|
|
12
12
|
private formatStatus;
|
|
13
13
|
}
|
|
@@ -4,6 +4,12 @@ import { BaseCommand } from '../../lib/base-command.js';
|
|
|
4
4
|
import { createClientFromConfig } from '../../lib/kalshi/index.js';
|
|
5
5
|
import { logger } from '../../lib/logger.js';
|
|
6
6
|
export default class MarketsShow extends BaseCommand {
|
|
7
|
+
static args = {
|
|
8
|
+
ticker: Args.string({
|
|
9
|
+
description: 'Market ticker symbol',
|
|
10
|
+
required: true,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
7
13
|
static description = 'Show market details';
|
|
8
14
|
static examples = [
|
|
9
15
|
'<%= config.bin %> <%= command.id %> TICKER',
|
|
@@ -12,12 +18,6 @@ export default class MarketsShow extends BaseCommand {
|
|
|
12
18
|
static flags = {
|
|
13
19
|
...BaseCommand.baseFlags,
|
|
14
20
|
};
|
|
15
|
-
static args = {
|
|
16
|
-
ticker: Args.string({
|
|
17
|
-
description: 'Market ticker symbol',
|
|
18
|
-
required: true,
|
|
19
|
-
}),
|
|
20
|
-
};
|
|
21
21
|
async run() {
|
|
22
22
|
const { args } = await this.parse(MarketsShow);
|
|
23
23
|
try {
|
|
@@ -70,8 +70,8 @@ export default class MarketsShow extends BaseCommand {
|
|
|
70
70
|
const colors = {
|
|
71
71
|
active: chalk.green,
|
|
72
72
|
closed: chalk.yellow,
|
|
73
|
-
settled: chalk.blue,
|
|
74
73
|
finalized: chalk.gray,
|
|
74
|
+
settled: chalk.blue,
|
|
75
75
|
};
|
|
76
76
|
const colorFn = colors[status] || chalk.white;
|
|
77
77
|
return colorFn(status);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { BaseCommand } from '../../lib/base-command.js';
|
|
2
2
|
export default class OrdersCancel extends BaseCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
orderId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
3
6
|
static description: string;
|
|
4
7
|
static examples: string[];
|
|
5
8
|
static flags: {
|
|
6
9
|
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
10
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
11
|
};
|
|
9
|
-
static args: {
|
|
10
|
-
orderId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
|
-
};
|
|
12
12
|
run(): Promise<void>;
|
|
13
13
|
private confirm;
|
|
14
14
|
}
|
|
@@ -5,6 +5,12 @@ import { getConfig } from '../../lib/config/manager.js';
|
|
|
5
5
|
import { createClientFromConfig } from '../../lib/kalshi/index.js';
|
|
6
6
|
import { logger } from '../../lib/logger.js';
|
|
7
7
|
export default class OrdersCancel extends BaseCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
orderId: Args.string({
|
|
10
|
+
description: 'Order ID to cancel',
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
8
14
|
static description = 'Cancel an order';
|
|
9
15
|
static examples = [
|
|
10
16
|
'<%= config.bin %> <%= command.id %> ORDER_ID',
|
|
@@ -15,14 +21,8 @@ export default class OrdersCancel extends BaseCommand {
|
|
|
15
21
|
...BaseCommand.baseFlags,
|
|
16
22
|
yes: Flags.boolean({
|
|
17
23
|
char: 'y',
|
|
18
|
-
description: 'Skip confirmation prompt',
|
|
19
24
|
default: false,
|
|
20
|
-
|
|
21
|
-
};
|
|
22
|
-
static args = {
|
|
23
|
-
orderId: Args.string({
|
|
24
|
-
description: 'Order ID to cancel',
|
|
25
|
-
required: true,
|
|
25
|
+
description: 'Skip confirmation prompt',
|
|
26
26
|
}),
|
|
27
27
|
};
|
|
28
28
|
async run() {
|
|
@@ -3,17 +3,17 @@ export default class OrdersCreate extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
-
ticker: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
6
|
action: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
|
|
7
|
+
'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
price: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
quantity: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
side: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
ticker: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
12
|
type: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
-
price: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
13
|
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
-
'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
14
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
15
|
};
|
|
16
16
|
run(): Promise<void>;
|
|
17
|
-
private formatStatus;
|
|
18
17
|
private confirm;
|
|
18
|
+
private formatStatus;
|
|
19
19
|
}
|
|
@@ -16,45 +16,45 @@ export default class OrdersCreate extends BaseCommand {
|
|
|
16
16
|
];
|
|
17
17
|
static flags = {
|
|
18
18
|
...BaseCommand.baseFlags,
|
|
19
|
-
ticker: Flags.string({
|
|
20
|
-
char: 't',
|
|
21
|
-
description: 'Market ticker symbol',
|
|
22
|
-
required: true,
|
|
23
|
-
}),
|
|
24
19
|
action: Flags.string({
|
|
25
20
|
char: 'a',
|
|
26
21
|
description: 'Order action (buy or sell)',
|
|
27
22
|
options: ['buy', 'sell'],
|
|
28
23
|
required: true,
|
|
29
24
|
}),
|
|
25
|
+
'dry-run': Flags.boolean({
|
|
26
|
+
default: false,
|
|
27
|
+
description: 'Simulate the order without actually placing it',
|
|
28
|
+
}),
|
|
29
|
+
price: Flags.string({
|
|
30
|
+
char: 'p',
|
|
31
|
+
description: 'Limit price (required for limit orders, 0.01-0.99)',
|
|
32
|
+
}),
|
|
33
|
+
quantity: Flags.integer({
|
|
34
|
+
char: 'q',
|
|
35
|
+
description: 'Number of contracts',
|
|
36
|
+
required: true,
|
|
37
|
+
}),
|
|
30
38
|
side: Flags.string({
|
|
31
39
|
char: 's',
|
|
32
40
|
description: 'Contract side (yes or no)',
|
|
33
41
|
options: ['yes', 'no'],
|
|
34
42
|
required: true,
|
|
35
43
|
}),
|
|
36
|
-
|
|
37
|
-
char: '
|
|
38
|
-
description: '
|
|
44
|
+
ticker: Flags.string({
|
|
45
|
+
char: 't',
|
|
46
|
+
description: 'Market ticker symbol',
|
|
39
47
|
required: true,
|
|
40
48
|
}),
|
|
41
49
|
type: Flags.string({
|
|
50
|
+
default: 'market',
|
|
42
51
|
description: 'Order type (market or limit)',
|
|
43
52
|
options: ['market', 'limit'],
|
|
44
|
-
default: 'market',
|
|
45
|
-
}),
|
|
46
|
-
price: Flags.string({
|
|
47
|
-
char: 'p',
|
|
48
|
-
description: 'Limit price (required for limit orders, 0.01-0.99)',
|
|
49
53
|
}),
|
|
50
54
|
yes: Flags.boolean({
|
|
51
55
|
char: 'y',
|
|
52
|
-
description: 'Skip confirmation prompt',
|
|
53
|
-
default: false,
|
|
54
|
-
}),
|
|
55
|
-
'dry-run': Flags.boolean({
|
|
56
|
-
description: 'Simulate the order without actually placing it',
|
|
57
56
|
default: false,
|
|
57
|
+
description: 'Skip confirmation prompt',
|
|
58
58
|
}),
|
|
59
59
|
};
|
|
60
60
|
async run() {
|
|
@@ -84,10 +84,10 @@ export default class OrdersCreate extends BaseCommand {
|
|
|
84
84
|
const costEstimate = estimateOrderCost(side, action, flags.quantity, price);
|
|
85
85
|
// Build order request
|
|
86
86
|
const orderRequest = {
|
|
87
|
-
ticker: flags.ticker,
|
|
88
|
-
side,
|
|
89
87
|
action,
|
|
90
88
|
count: flags.quantity,
|
|
89
|
+
side,
|
|
90
|
+
ticker: flags.ticker,
|
|
91
91
|
type: orderType,
|
|
92
92
|
};
|
|
93
93
|
if (orderType === 'limit' && price) {
|
|
@@ -132,16 +132,16 @@ export default class OrdersCreate extends BaseCommand {
|
|
|
132
132
|
if (flags['dry-run']) {
|
|
133
133
|
if (this.formatter.isJSONMode()) {
|
|
134
134
|
this.formatter.success({
|
|
135
|
+
costEstimate,
|
|
135
136
|
dryRun: true,
|
|
136
137
|
order: orderRequest,
|
|
137
|
-
costEstimate,
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
else {
|
|
141
141
|
this.log(chalk.yellow('DRY RUN - Order not placed'));
|
|
142
142
|
this.log(chalk.gray('Order would be submitted with the parameters above'));
|
|
143
143
|
}
|
|
144
|
-
logger.info({
|
|
144
|
+
logger.info({ dryRun: true, orderRequest }, 'Dry run order');
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
147
|
// Confirmation prompt (unless --yes flag or JSON mode)
|
|
@@ -187,17 +187,6 @@ export default class OrdersCreate extends BaseCommand {
|
|
|
187
187
|
throw error;
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
-
formatStatus(status) {
|
|
191
|
-
const colors = {
|
|
192
|
-
executed: chalk.green,
|
|
193
|
-
pending: chalk.yellow,
|
|
194
|
-
resting: chalk.cyan,
|
|
195
|
-
canceled: chalk.gray,
|
|
196
|
-
expired: chalk.red,
|
|
197
|
-
};
|
|
198
|
-
const colorFn = colors[status] || chalk.white;
|
|
199
|
-
return colorFn(status);
|
|
200
|
-
}
|
|
201
190
|
async confirm(message) {
|
|
202
191
|
const readline = await import('node:readline/promises');
|
|
203
192
|
const rl = readline.createInterface({
|
|
@@ -208,4 +197,15 @@ export default class OrdersCreate extends BaseCommand {
|
|
|
208
197
|
rl.close();
|
|
209
198
|
return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
|
|
210
199
|
}
|
|
200
|
+
formatStatus(status) {
|
|
201
|
+
const colors = {
|
|
202
|
+
canceled: chalk.gray,
|
|
203
|
+
executed: chalk.green,
|
|
204
|
+
expired: chalk.red,
|
|
205
|
+
pending: chalk.yellow,
|
|
206
|
+
resting: chalk.cyan,
|
|
207
|
+
};
|
|
208
|
+
const colorFn = colors[status] || chalk.white;
|
|
209
|
+
return colorFn(status);
|
|
210
|
+
}
|
|
211
211
|
}
|
|
@@ -3,9 +3,9 @@ export default class OrdersList extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
+
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
7
|
status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
8
|
ticker: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
10
|
};
|
|
11
11
|
run(): Promise<void>;
|
|
@@ -13,6 +13,10 @@ export default class OrdersList extends BaseCommand {
|
|
|
13
13
|
];
|
|
14
14
|
static flags = {
|
|
15
15
|
...BaseCommand.baseFlags,
|
|
16
|
+
limit: Flags.integer({
|
|
17
|
+
default: 50,
|
|
18
|
+
description: 'Maximum number of orders to return',
|
|
19
|
+
}),
|
|
16
20
|
status: Flags.string({
|
|
17
21
|
description: 'Filter by order status',
|
|
18
22
|
options: ['pending', 'resting', 'canceled', 'executed', 'expired'],
|
|
@@ -20,10 +24,6 @@ export default class OrdersList extends BaseCommand {
|
|
|
20
24
|
ticker: Flags.string({
|
|
21
25
|
description: 'Filter by ticker',
|
|
22
26
|
}),
|
|
23
|
-
limit: Flags.integer({
|
|
24
|
-
description: 'Maximum number of orders to return',
|
|
25
|
-
default: 50,
|
|
26
|
-
}),
|
|
27
27
|
};
|
|
28
28
|
async run() {
|
|
29
29
|
const { flags } = await this.parse(OrdersList);
|
|
@@ -32,13 +32,13 @@ export default class OrdersList extends BaseCommand {
|
|
|
32
32
|
const client = createClientFromConfig();
|
|
33
33
|
// Fetch orders
|
|
34
34
|
const result = await client.getOrders({
|
|
35
|
+
limit: flags.limit,
|
|
35
36
|
status: flags.status,
|
|
36
37
|
ticker: flags.ticker,
|
|
37
|
-
limit: flags.limit,
|
|
38
38
|
});
|
|
39
|
-
const orders = result
|
|
39
|
+
const { orders } = result;
|
|
40
40
|
if (this.formatter.isJSONMode()) {
|
|
41
|
-
this.formatter.success({
|
|
41
|
+
this.formatter.success({ cursor: result.cursor, orders });
|
|
42
42
|
}
|
|
43
43
|
else {
|
|
44
44
|
if (orders.length === 0) {
|
|
@@ -80,11 +80,11 @@ export default class OrdersList extends BaseCommand {
|
|
|
80
80
|
}
|
|
81
81
|
formatStatus(status) {
|
|
82
82
|
const colors = {
|
|
83
|
+
canceled: chalk.gray,
|
|
83
84
|
executed: chalk.green,
|
|
85
|
+
expired: chalk.red,
|
|
84
86
|
pending: chalk.yellow,
|
|
85
87
|
resting: chalk.cyan,
|
|
86
|
-
canceled: chalk.gray,
|
|
87
|
-
expired: chalk.red,
|
|
88
88
|
};
|
|
89
89
|
const colorFn = colors[status] || chalk.white;
|
|
90
90
|
return colorFn(status);
|