@gaberoo/kalshitools 1.0.1 → 1.0.3
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 +91 -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/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/balance.js +11 -6
- package/dist/commands/portfolio/fills.d.ts +1 -1
- package/dist/commands/portfolio/fills.js +7 -7
- package/dist/commands/portfolio/positions.d.ts +1 -0
- package/dist/commands/portfolio/positions.js +11 -2
- 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 +101 -86
- package/dist/lib/kalshi/index.d.ts +1 -1
- package/dist/lib/kalshi/index.js +1 -1
- package/dist/lib/kalshi/types.d.ts +54 -54
- 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/sanitize.js +9 -9
- 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/oclif.manifest.json +138 -47
- package/package.json +1 -1
|
@@ -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);
|
|
@@ -15,18 +15,23 @@ export default class PortfolioBalance extends BaseCommand {
|
|
|
15
15
|
const client = createClientFromConfig();
|
|
16
16
|
// Fetch balance
|
|
17
17
|
const balance = await client.getBalance();
|
|
18
|
+
// Convert cents to dollars
|
|
19
|
+
const balanceDollars = balance.balance / 100;
|
|
20
|
+
const portfolioValueDollars = balance.portfolio_value / 100;
|
|
18
21
|
if (this.formatter.isJSONMode()) {
|
|
19
|
-
|
|
22
|
+
// Return in dollars for readability
|
|
23
|
+
this.formatter.success({
|
|
24
|
+
balance: balanceDollars,
|
|
25
|
+
portfolio_value: portfolioValueDollars,
|
|
26
|
+
});
|
|
20
27
|
}
|
|
21
28
|
else {
|
|
22
29
|
this.log(chalk.cyan.bold('Account Balance'));
|
|
23
30
|
this.log();
|
|
24
|
-
this.log(`${chalk.cyan('
|
|
25
|
-
this.log(`${chalk.cyan('
|
|
26
|
-
this.log();
|
|
27
|
-
this.log(chalk.gray(`Total: $${(balance.balance + balance.payout).toFixed(2)}`));
|
|
31
|
+
this.log(`${chalk.cyan('Available:')} ${chalk.green('$' + balanceDollars.toFixed(2))}`);
|
|
32
|
+
this.log(`${chalk.cyan('Portfolio Value:')} ${chalk.yellow('$' + portfolioValueDollars.toFixed(2))}`);
|
|
28
33
|
}
|
|
29
|
-
logger.info({ balance:
|
|
34
|
+
logger.info({ balance: balanceDollars, portfolio_value: portfolioValueDollars }, 'Balance fetched successfully');
|
|
30
35
|
}
|
|
31
36
|
catch (error) {
|
|
32
37
|
// Error will be handled by BaseCommand.catch()
|
|
@@ -3,8 +3,8 @@ export default class PortfolioFills extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
-
ticker: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
6
|
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
ticker: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
8
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
9
|
};
|
|
10
10
|
run(): Promise<void>;
|
|
@@ -13,12 +13,12 @@ export default class PortfolioFills extends BaseCommand {
|
|
|
13
13
|
];
|
|
14
14
|
static flags = {
|
|
15
15
|
...BaseCommand.baseFlags,
|
|
16
|
-
ticker: Flags.string({
|
|
17
|
-
description: 'Filter by ticker',
|
|
18
|
-
}),
|
|
19
16
|
limit: Flags.integer({
|
|
20
|
-
description: 'Maximum number of fills to return',
|
|
21
17
|
default: 50,
|
|
18
|
+
description: 'Maximum number of fills to return',
|
|
19
|
+
}),
|
|
20
|
+
ticker: Flags.string({
|
|
21
|
+
description: 'Filter by ticker',
|
|
22
22
|
}),
|
|
23
23
|
};
|
|
24
24
|
async run() {
|
|
@@ -28,12 +28,12 @@ export default class PortfolioFills extends BaseCommand {
|
|
|
28
28
|
const client = createClientFromConfig();
|
|
29
29
|
// Fetch fills
|
|
30
30
|
const result = await client.getFills({
|
|
31
|
-
ticker: flags.ticker,
|
|
32
31
|
limit: flags.limit,
|
|
32
|
+
ticker: flags.ticker,
|
|
33
33
|
});
|
|
34
|
-
const fills = result
|
|
34
|
+
const { fills } = result;
|
|
35
35
|
if (this.formatter.isJSONMode()) {
|
|
36
|
-
this.formatter.success({
|
|
36
|
+
this.formatter.success({ cursor: result.cursor, fills });
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
39
39
|
if (fills.length === 0) {
|
|
@@ -3,6 +3,7 @@ export default class PortfolioPositions extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
+
'settlement-status': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
7
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
8
|
};
|
|
8
9
|
run(): Promise<void>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import { BaseCommand } from '../../lib/base-command.js';
|
|
3
4
|
import { createClientFromConfig } from '../../lib/kalshi/index.js';
|
|
@@ -6,18 +7,26 @@ export default class PortfolioPositions extends BaseCommand {
|
|
|
6
7
|
static description = 'View current positions with P&L';
|
|
7
8
|
static examples = [
|
|
8
9
|
'<%= config.bin %> <%= command.id %>',
|
|
10
|
+
'<%= config.bin %> <%= command.id %> --settlement-status open',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> --settlement-status settled',
|
|
9
12
|
'<%= config.bin %> <%= command.id %> --json',
|
|
10
13
|
];
|
|
11
14
|
static flags = {
|
|
12
15
|
...BaseCommand.baseFlags,
|
|
16
|
+
'settlement-status': Flags.string({
|
|
17
|
+
description: 'Filter by settlement status',
|
|
18
|
+
options: ['open', 'pending', 'settled'],
|
|
19
|
+
}),
|
|
13
20
|
};
|
|
14
21
|
async run() {
|
|
15
|
-
await this.parse(PortfolioPositions);
|
|
22
|
+
const { flags } = await this.parse(PortfolioPositions);
|
|
16
23
|
try {
|
|
17
24
|
// Create API client from configuration
|
|
18
25
|
const client = createClientFromConfig();
|
|
19
26
|
// Fetch positions
|
|
20
|
-
const positions = await client.getPositions(
|
|
27
|
+
const positions = await client.getPositions({
|
|
28
|
+
settlement_status: flags['settlement-status'],
|
|
29
|
+
});
|
|
21
30
|
if (this.formatter.isJSONMode()) {
|
|
22
31
|
this.formatter.success(positions);
|
|
23
32
|
}
|
|
@@ -4,10 +4,10 @@ import { OutputFormatter } from './output/formatter.js';
|
|
|
4
4
|
* Base command class that all kalshitools commands extend
|
|
5
5
|
*/
|
|
6
6
|
export declare abstract class BaseCommand extends Command {
|
|
7
|
-
protected formatter: OutputFormatter;
|
|
8
7
|
static baseFlags: {
|
|
9
8
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
9
|
};
|
|
11
|
-
|
|
10
|
+
protected formatter: OutputFormatter;
|
|
12
11
|
protected catch(error: Error): Promise<unknown>;
|
|
12
|
+
init(): Promise<void>;
|
|
13
13
|
}
|
package/dist/lib/base-command.js
CHANGED
|
@@ -6,20 +6,15 @@ import { OutputFormatter } from './output/formatter.js';
|
|
|
6
6
|
* Base command class that all kalshitools commands extend
|
|
7
7
|
*/
|
|
8
8
|
export class BaseCommand extends Command {
|
|
9
|
-
formatter;
|
|
10
9
|
static baseFlags = {
|
|
11
10
|
json: Flags.boolean({
|
|
12
|
-
description: 'Output in JSON format',
|
|
13
11
|
default: false,
|
|
12
|
+
description: 'Output in JSON format',
|
|
14
13
|
}),
|
|
15
14
|
};
|
|
16
|
-
|
|
17
|
-
await super.init();
|
|
18
|
-
const { flags } = await this.parse(this.constructor);
|
|
19
|
-
this.formatter = new OutputFormatter(flags.json, this.id);
|
|
20
|
-
}
|
|
15
|
+
formatter;
|
|
21
16
|
async catch(error) {
|
|
22
|
-
logger.error({
|
|
17
|
+
logger.error({ command: this.id, error }, 'Command failed');
|
|
23
18
|
if (error instanceof KalshiToolsError) {
|
|
24
19
|
if (this.formatter?.isJSONMode()) {
|
|
25
20
|
this.formatter.error(error.code, error.message, error.details);
|
|
@@ -35,4 +30,9 @@ export class BaseCommand extends Command {
|
|
|
35
30
|
}
|
|
36
31
|
throw error;
|
|
37
32
|
}
|
|
33
|
+
async init() {
|
|
34
|
+
await super.init();
|
|
35
|
+
const { flags } = await this.parse(this.constructor);
|
|
36
|
+
this.formatter = new OutputFormatter(flags.json, this.id);
|
|
37
|
+
}
|
|
38
38
|
}
|
|
@@ -1,45 +1,37 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ApiEnvConfig, type Config } from './schema.js';
|
|
2
2
|
/**
|
|
3
3
|
* Configuration manager for kalshitools
|
|
4
4
|
*/
|
|
5
5
|
export declare class ConfigManager {
|
|
6
|
-
private store;
|
|
7
6
|
private static instance;
|
|
7
|
+
private store;
|
|
8
8
|
constructor();
|
|
9
9
|
/**
|
|
10
10
|
* Get singleton instance
|
|
11
11
|
*/
|
|
12
12
|
static getInstance(): ConfigManager;
|
|
13
|
-
/**
|
|
14
|
-
* Get the full configuration
|
|
15
|
-
*/
|
|
16
|
-
getConfig(): Config;
|
|
17
|
-
/**
|
|
18
|
-
* Get the current environment (demo or production)
|
|
19
|
-
*/
|
|
20
|
-
getEnvironment(): 'demo' | 'production';
|
|
21
|
-
/**
|
|
22
|
-
* Set the environment
|
|
23
|
-
*/
|
|
24
|
-
setEnvironment(env: 'demo' | 'production'): void;
|
|
25
13
|
/**
|
|
26
14
|
* Get API configuration for the current environment
|
|
27
15
|
*/
|
|
28
16
|
getApiConfig(): ApiEnvConfig;
|
|
29
17
|
/**
|
|
30
|
-
*
|
|
18
|
+
* Get the full configuration
|
|
31
19
|
*/
|
|
32
|
-
|
|
20
|
+
getConfig(): Config;
|
|
33
21
|
/**
|
|
34
|
-
*
|
|
22
|
+
* Get the configuration file path
|
|
35
23
|
*/
|
|
36
|
-
|
|
24
|
+
getConfigPath(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Get the current environment (demo or production)
|
|
27
|
+
*/
|
|
28
|
+
getEnvironment(): 'demo' | 'production';
|
|
37
29
|
/**
|
|
38
30
|
* Get output configuration
|
|
39
31
|
*/
|
|
40
32
|
getOutputConfig(): {
|
|
41
|
-
defaultFormat: "json" | "table";
|
|
42
33
|
colors: boolean;
|
|
34
|
+
defaultFormat: "json" | "table";
|
|
43
35
|
};
|
|
44
36
|
/**
|
|
45
37
|
* Get trading configuration
|
|
@@ -49,21 +41,29 @@ export declare class ConfigManager {
|
|
|
49
41
|
maxOrderSize: number;
|
|
50
42
|
};
|
|
51
43
|
/**
|
|
52
|
-
*
|
|
44
|
+
* Check if configuration is initialized
|
|
53
45
|
*/
|
|
54
|
-
|
|
46
|
+
isConfigured(): boolean;
|
|
55
47
|
/**
|
|
56
|
-
*
|
|
48
|
+
* Read private key from file
|
|
57
49
|
*/
|
|
58
|
-
|
|
50
|
+
readPrivateKey(): string;
|
|
59
51
|
/**
|
|
60
52
|
* Reset configuration to defaults
|
|
61
53
|
*/
|
|
62
54
|
reset(): void;
|
|
63
55
|
/**
|
|
64
|
-
*
|
|
56
|
+
* Set a configuration value
|
|
65
57
|
*/
|
|
66
|
-
|
|
58
|
+
set<K extends keyof Config>(key: K, value: Config[K]): void;
|
|
59
|
+
/**
|
|
60
|
+
* Set API configuration for an environment
|
|
61
|
+
*/
|
|
62
|
+
setApiConfig(env: 'demo' | 'production', config: Partial<ApiEnvConfig>): void;
|
|
63
|
+
/**
|
|
64
|
+
* Set the environment
|
|
65
|
+
*/
|
|
66
|
+
setEnvironment(env: 'demo' | 'production'): void;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Get the global configuration manager instance
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import Conf from 'conf';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
4
|
import { join } from 'node:path';
|
|
4
|
-
import { readFileSync } from 'node:fs';
|
|
5
|
-
import { defaultConfig } from './schema.js';
|
|
6
5
|
import { ConfigError } from '../errors/base.js';
|
|
7
6
|
import { logger } from '../logger.js';
|
|
7
|
+
import { defaultConfig } from './schema.js';
|
|
8
8
|
/**
|
|
9
9
|
* Configuration manager for kalshitools
|
|
10
10
|
*/
|
|
11
11
|
export class ConfigManager {
|
|
12
|
-
store;
|
|
13
12
|
static instance = null;
|
|
13
|
+
store;
|
|
14
14
|
constructor() {
|
|
15
15
|
this.store = new Conf({
|
|
16
|
-
projectName: 'kalshitools',
|
|
17
16
|
defaults: defaultConfig,
|
|
17
|
+
projectName: 'kalshitools',
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
@@ -26,6 +26,24 @@ export class ConfigManager {
|
|
|
26
26
|
}
|
|
27
27
|
return ConfigManager.instance;
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Get API configuration for the current environment
|
|
31
|
+
*/
|
|
32
|
+
getApiConfig() {
|
|
33
|
+
const env = this.getEnvironment();
|
|
34
|
+
const config = this.store.get(`api.${env}`);
|
|
35
|
+
// Override with environment variables if present
|
|
36
|
+
const keyId = process.env.KALSHI_API_KEY_ID || config.keyId;
|
|
37
|
+
const privateKeyPath = process.env.KALSHI_PRIVATE_KEY_PATH || config.privateKeyPath;
|
|
38
|
+
if (!keyId || !privateKeyPath) {
|
|
39
|
+
throw new ConfigError(`API credentials not configured for ${env} environment. Run 'kalshitools config init' to set up.`, { environment: env });
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
baseUrl: config.baseUrl,
|
|
43
|
+
keyId,
|
|
44
|
+
privateKeyPath,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
29
47
|
/**
|
|
30
48
|
* Get the full configuration
|
|
31
49
|
*/
|
|
@@ -33,6 +51,12 @@ export class ConfigManager {
|
|
|
33
51
|
const config = this.store.store;
|
|
34
52
|
return config;
|
|
35
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the configuration file path
|
|
56
|
+
*/
|
|
57
|
+
getConfigPath() {
|
|
58
|
+
return this.store.path;
|
|
59
|
+
}
|
|
36
60
|
/**
|
|
37
61
|
* Get the current environment (demo or production)
|
|
38
62
|
*/
|
|
@@ -40,28 +64,24 @@ export class ConfigManager {
|
|
|
40
64
|
return process.env.KALSHI_ENV === 'production' ? 'production' : this.store.get('environment', 'demo');
|
|
41
65
|
}
|
|
42
66
|
/**
|
|
43
|
-
*
|
|
67
|
+
* Get output configuration
|
|
44
68
|
*/
|
|
45
|
-
|
|
46
|
-
this.store.
|
|
69
|
+
getOutputConfig() {
|
|
70
|
+
return this.store.get('output');
|
|
47
71
|
}
|
|
48
72
|
/**
|
|
49
|
-
* Get
|
|
73
|
+
* Get trading configuration
|
|
50
74
|
*/
|
|
51
|
-
|
|
75
|
+
getTradingConfig() {
|
|
76
|
+
return this.store.get('trading');
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check if configuration is initialized
|
|
80
|
+
*/
|
|
81
|
+
isConfigured() {
|
|
52
82
|
const env = this.getEnvironment();
|
|
53
83
|
const config = this.store.get(`api.${env}`);
|
|
54
|
-
|
|
55
|
-
const keyId = process.env.KALSHI_API_KEY_ID || config.keyId;
|
|
56
|
-
const privateKeyPath = process.env.KALSHI_PRIVATE_KEY_PATH || config.privateKeyPath;
|
|
57
|
-
if (!keyId || !privateKeyPath) {
|
|
58
|
-
throw new ConfigError(`API credentials not configured for ${env} environment. Run 'kalshitools config init' to set up.`, { environment: env });
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
baseUrl: config.baseUrl,
|
|
62
|
-
keyId,
|
|
63
|
-
privateKeyPath,
|
|
64
|
-
};
|
|
84
|
+
return Boolean(config.keyId && config.privateKeyPath);
|
|
65
85
|
}
|
|
66
86
|
/**
|
|
67
87
|
* Read private key from file
|
|
@@ -78,29 +98,16 @@ export class ConfigManager {
|
|
|
78
98
|
}
|
|
79
99
|
catch (error) {
|
|
80
100
|
throw new ConfigError(`Failed to read private key from ${expandedPath}`, {
|
|
81
|
-
path: expandedPath,
|
|
82
101
|
error: error instanceof Error ? error.message : String(error),
|
|
102
|
+
path: expandedPath,
|
|
83
103
|
});
|
|
84
104
|
}
|
|
85
105
|
}
|
|
86
106
|
/**
|
|
87
|
-
*
|
|
88
|
-
*/
|
|
89
|
-
setApiConfig(env, config) {
|
|
90
|
-
const current = this.store.get(`api.${env}`);
|
|
91
|
-
this.store.set(`api.${env}`, { ...current, ...config });
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Get output configuration
|
|
95
|
-
*/
|
|
96
|
-
getOutputConfig() {
|
|
97
|
-
return this.store.get('output');
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Get trading configuration
|
|
107
|
+
* Reset configuration to defaults
|
|
101
108
|
*/
|
|
102
|
-
|
|
103
|
-
|
|
109
|
+
reset() {
|
|
110
|
+
this.store.clear();
|
|
104
111
|
}
|
|
105
112
|
/**
|
|
106
113
|
* Set a configuration value
|
|
@@ -109,24 +116,17 @@ export class ConfigManager {
|
|
|
109
116
|
this.store.set(key, value);
|
|
110
117
|
}
|
|
111
118
|
/**
|
|
112
|
-
*
|
|
113
|
-
*/
|
|
114
|
-
getConfigPath() {
|
|
115
|
-
return this.store.path;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Reset configuration to defaults
|
|
119
|
+
* Set API configuration for an environment
|
|
119
120
|
*/
|
|
120
|
-
|
|
121
|
-
this.store.
|
|
121
|
+
setApiConfig(env, config) {
|
|
122
|
+
const current = this.store.get(`api.${env}`);
|
|
123
|
+
this.store.set(`api.${env}`, { ...current, ...config });
|
|
122
124
|
}
|
|
123
125
|
/**
|
|
124
|
-
*
|
|
126
|
+
* Set the environment
|
|
125
127
|
*/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const config = this.store.get(`api.${env}`);
|
|
129
|
-
return Boolean(config.keyId && config.privateKeyPath);
|
|
128
|
+
setEnvironment(env) {
|
|
129
|
+
this.store.set('environment', env);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
/**
|