@megatao/sdk 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.
Files changed (228) hide show
  1. package/.env.example +37 -0
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +199 -0
  4. package/bin/alf +4 -0
  5. package/cli/README.md +198 -0
  6. package/cli/TEST_MANUAL.md +577 -0
  7. package/cli/commands/account.ts +545 -0
  8. package/cli/commands/funding.ts +481 -0
  9. package/cli/commands/liquidation.ts +523 -0
  10. package/cli/commands/market.ts +590 -0
  11. package/cli/commands/orders.ts +395 -0
  12. package/cli/commands/position.ts +1085 -0
  13. package/cli/commands/shared/positionUtils.ts +239 -0
  14. package/cli/commands/trading.ts +483 -0
  15. package/cli/commands/utils.ts +281 -0
  16. package/cli/commands/vault.ts +522 -0
  17. package/cli/index.ts +169 -0
  18. package/cli/interactive.ts +530 -0
  19. package/cli/utils/client.ts +457 -0
  20. package/cli/utils/config.ts +226 -0
  21. package/cli/utils/display.ts +258 -0
  22. package/cli/utils/index.ts +10 -0
  23. package/cli/utils/prompts.ts +364 -0
  24. package/config.example.json +23 -0
  25. package/dist/AlphaFuturesClient.d.ts +36 -0
  26. package/dist/AlphaFuturesClient.d.ts.map +1 -0
  27. package/dist/AlphaFuturesClient.js +116 -0
  28. package/dist/AlphaFuturesClient.js.map +1 -0
  29. package/dist/abi/Alpha.json +5987 -0
  30. package/dist/abi/abis.d.ts +319 -0
  31. package/dist/abi/abis.d.ts.map +1 -0
  32. package/dist/abi/abis.js +128 -0
  33. package/dist/abi/abis.js.map +1 -0
  34. package/dist/abi/index.d.ts +11 -0
  35. package/dist/abi/index.d.ts.map +1 -0
  36. package/dist/abi/index.js +15 -0
  37. package/dist/abi/index.js.map +1 -0
  38. package/dist/config/contracts.config.d.ts +70 -0
  39. package/dist/config/contracts.config.d.ts.map +1 -0
  40. package/dist/config/contracts.config.js +137 -0
  41. package/dist/config/contracts.config.js.map +1 -0
  42. package/dist/config/environments/alpha.config.d.ts +17 -0
  43. package/dist/config/environments/alpha.config.d.ts.map +1 -0
  44. package/dist/config/environments/alpha.config.js +140 -0
  45. package/dist/config/environments/alpha.config.js.map +1 -0
  46. package/dist/config/environments/beta.config.d.ts +16 -0
  47. package/dist/config/environments/beta.config.d.ts.map +1 -0
  48. package/dist/config/environments/beta.config.js +131 -0
  49. package/dist/config/environments/beta.config.js.map +1 -0
  50. package/dist/config/environments/dev.config.d.ts +13 -0
  51. package/dist/config/environments/dev.config.d.ts.map +1 -0
  52. package/dist/config/environments/dev.config.js +123 -0
  53. package/dist/config/environments/dev.config.js.map +1 -0
  54. package/dist/config/environments/index.d.ts +48 -0
  55. package/dist/config/environments/index.d.ts.map +1 -0
  56. package/dist/config/environments/index.js +81 -0
  57. package/dist/config/environments/index.js.map +1 -0
  58. package/dist/config/environments/localhost.config.d.ts +16 -0
  59. package/dist/config/environments/localhost.config.d.ts.map +1 -0
  60. package/dist/config/environments/localhost.config.js +152 -0
  61. package/dist/config/environments/localhost.config.js.map +1 -0
  62. package/dist/config/environments/prod.config.d.ts +20 -0
  63. package/dist/config/environments/prod.config.d.ts.map +1 -0
  64. package/dist/config/environments/prod.config.js +143 -0
  65. package/dist/config/environments/prod.config.js.map +1 -0
  66. package/dist/config/index.d.ts +7 -0
  67. package/dist/config/index.d.ts.map +1 -0
  68. package/dist/config/index.js +41 -0
  69. package/dist/config/index.js.map +1 -0
  70. package/dist/constants/assets.d.ts +76 -0
  71. package/dist/constants/assets.d.ts.map +1 -0
  72. package/dist/constants/assets.js +277 -0
  73. package/dist/constants/assets.js.map +1 -0
  74. package/dist/constants/contracts.d.ts +41 -0
  75. package/dist/constants/contracts.d.ts.map +1 -0
  76. package/dist/constants/contracts.js +57 -0
  77. package/dist/constants/contracts.js.map +1 -0
  78. package/dist/constants/index.d.ts +36 -0
  79. package/dist/constants/index.d.ts.map +1 -0
  80. package/dist/constants/index.js +75 -0
  81. package/dist/constants/index.js.map +1 -0
  82. package/dist/constants/networks.d.ts +32 -0
  83. package/dist/constants/networks.d.ts.map +1 -0
  84. package/dist/constants/networks.js +174 -0
  85. package/dist/constants/networks.js.map +1 -0
  86. package/dist/contracts/index.d.ts +5 -0
  87. package/dist/contracts/index.d.ts.map +1 -0
  88. package/dist/contracts/index.js +21 -0
  89. package/dist/contracts/index.js.map +1 -0
  90. package/dist/contracts/viem/AlphaViem.d.ts +518 -0
  91. package/dist/contracts/viem/AlphaViem.d.ts.map +1 -0
  92. package/dist/contracts/viem/AlphaViem.js +1287 -0
  93. package/dist/contracts/viem/AlphaViem.js.map +1 -0
  94. package/dist/contracts/viem/PriceOracleViem.d.ts +71 -0
  95. package/dist/contracts/viem/PriceOracleViem.d.ts.map +1 -0
  96. package/dist/contracts/viem/PriceOracleViem.js +212 -0
  97. package/dist/contracts/viem/PriceOracleViem.js.map +1 -0
  98. package/dist/contracts/viem/index.d.ts +9 -0
  99. package/dist/contracts/viem/index.d.ts.map +1 -0
  100. package/dist/contracts/viem/index.js +17 -0
  101. package/dist/contracts/viem/index.js.map +1 -0
  102. package/dist/errors/index.d.ts +44 -0
  103. package/dist/errors/index.d.ts.map +1 -0
  104. package/dist/errors/index.js +83 -0
  105. package/dist/errors/index.js.map +1 -0
  106. package/dist/index.d.ts +19 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +60 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/types/alpha.d.ts +299 -0
  111. package/dist/types/alpha.d.ts.map +1 -0
  112. package/dist/types/alpha.js +6 -0
  113. package/dist/types/alpha.js.map +1 -0
  114. package/dist/types/client.d.ts +24 -0
  115. package/dist/types/client.d.ts.map +1 -0
  116. package/dist/types/client.js +13 -0
  117. package/dist/types/client.js.map +1 -0
  118. package/dist/types/contracts.d.ts +48 -0
  119. package/dist/types/contracts.d.ts.map +1 -0
  120. package/dist/types/contracts.js +6 -0
  121. package/dist/types/contracts.js.map +1 -0
  122. package/dist/types/funding.d.ts +27 -0
  123. package/dist/types/funding.d.ts.map +1 -0
  124. package/dist/types/funding.js +6 -0
  125. package/dist/types/funding.js.map +1 -0
  126. package/dist/types/index.d.ts +92 -0
  127. package/dist/types/index.d.ts.map +1 -0
  128. package/dist/types/index.js +47 -0
  129. package/dist/types/index.js.map +1 -0
  130. package/dist/types/liquidation.d.ts +20 -0
  131. package/dist/types/liquidation.d.ts.map +1 -0
  132. package/dist/types/liquidation.js +6 -0
  133. package/dist/types/liquidation.js.map +1 -0
  134. package/dist/types/margin.d.ts +29 -0
  135. package/dist/types/margin.d.ts.map +1 -0
  136. package/dist/types/margin.js +6 -0
  137. package/dist/types/margin.js.map +1 -0
  138. package/dist/types/oracle.d.ts +21 -0
  139. package/dist/types/oracle.d.ts.map +1 -0
  140. package/dist/types/oracle.js +6 -0
  141. package/dist/types/oracle.js.map +1 -0
  142. package/dist/types/positions.d.ts +43 -0
  143. package/dist/types/positions.d.ts.map +1 -0
  144. package/dist/types/positions.js +13 -0
  145. package/dist/types/positions.js.map +1 -0
  146. package/dist/utils/calculations.d.ts +84 -0
  147. package/dist/utils/calculations.d.ts.map +1 -0
  148. package/dist/utils/calculations.js +155 -0
  149. package/dist/utils/calculations.js.map +1 -0
  150. package/dist/utils/errors.d.ts +24 -0
  151. package/dist/utils/errors.d.ts.map +1 -0
  152. package/dist/utils/errors.js +129 -0
  153. package/dist/utils/errors.js.map +1 -0
  154. package/dist/utils/events.d.ts +40 -0
  155. package/dist/utils/events.d.ts.map +1 -0
  156. package/dist/utils/events.js +73 -0
  157. package/dist/utils/events.js.map +1 -0
  158. package/dist/utils/format.d.ts +40 -0
  159. package/dist/utils/format.d.ts.map +1 -0
  160. package/dist/utils/format.js +86 -0
  161. package/dist/utils/format.js.map +1 -0
  162. package/dist/utils/index.d.ts +10 -0
  163. package/dist/utils/index.d.ts.map +1 -0
  164. package/dist/utils/index.js +26 -0
  165. package/dist/utils/index.js.map +1 -0
  166. package/dist/utils/network.d.ts +52 -0
  167. package/dist/utils/network.d.ts.map +1 -0
  168. package/dist/utils/network.js +192 -0
  169. package/dist/utils/network.js.map +1 -0
  170. package/dist/utils/positionCalculations.d.ts +145 -0
  171. package/dist/utils/positionCalculations.d.ts.map +1 -0
  172. package/dist/utils/positionCalculations.js +278 -0
  173. package/dist/utils/positionCalculations.js.map +1 -0
  174. package/dist/utils/validation.d.ts +28 -0
  175. package/dist/utils/validation.d.ts.map +1 -0
  176. package/dist/utils/validation.js +68 -0
  177. package/dist/utils/validation.js.map +1 -0
  178. package/docs/README.md +40 -0
  179. package/docs/api/API.md +831 -0
  180. package/docs/guides/GETTING_STARTED.md +316 -0
  181. package/docs/guides/TRADING_GUIDE.md +677 -0
  182. package/docs/integration/INTEGRATION_GUIDE.md +1679 -0
  183. package/docs/integration/VIEM_INTEGRATION.md +294 -0
  184. package/docs/reference/CLI_QUICK_REFERENCE.md +197 -0
  185. package/docs/reference/TROUBLESHOOTING.md +922 -0
  186. package/package.json +113 -0
  187. package/src/AlphaFuturesClient.ts +158 -0
  188. package/src/abi/.gitkeep +1 -0
  189. package/src/abi/Alpha.json +5987 -0
  190. package/src/abi/README.md +99 -0
  191. package/src/abi/abis.ts +131 -0
  192. package/src/abi/index.ts +13 -0
  193. package/src/config/contracts.config.ts +186 -0
  194. package/src/config/environments/alpha.config.ts +139 -0
  195. package/src/config/environments/beta.config.ts +130 -0
  196. package/src/config/environments/dev.config.ts +122 -0
  197. package/src/config/environments/index.ts +87 -0
  198. package/src/config/environments/localhost.config.ts +153 -0
  199. package/src/config/environments/prod.config.ts +142 -0
  200. package/src/config/index.ts +29 -0
  201. package/src/constants/assets.ts +299 -0
  202. package/src/constants/contracts.ts +64 -0
  203. package/src/constants/index.ts +69 -0
  204. package/src/constants/networks.ts +182 -0
  205. package/src/contracts/index.ts +5 -0
  206. package/src/contracts/viem/AlphaViem.ts +1615 -0
  207. package/src/contracts/viem/PriceOracleViem.ts +272 -0
  208. package/src/contracts/viem/index.ts +11 -0
  209. package/src/errors/index.ts +87 -0
  210. package/src/index.ts +59 -0
  211. package/src/types/VIEM_TYPES_README.md +70 -0
  212. package/src/types/alpha.ts +358 -0
  213. package/src/types/client.ts +27 -0
  214. package/src/types/contracts.ts +74 -0
  215. package/src/types/funding.ts +31 -0
  216. package/src/types/index.ts +108 -0
  217. package/src/types/liquidation.ts +23 -0
  218. package/src/types/margin.ts +34 -0
  219. package/src/types/oracle.ts +24 -0
  220. package/src/types/positions.ts +48 -0
  221. package/src/utils/calculations.ts +175 -0
  222. package/src/utils/errors.ts +147 -0
  223. package/src/utils/events.ts +98 -0
  224. package/src/utils/format.ts +84 -0
  225. package/src/utils/index.ts +10 -0
  226. package/src/utils/network.ts +212 -0
  227. package/src/utils/positionCalculations.ts +317 -0
  228. package/src/utils/validation.ts +76 -0
@@ -0,0 +1,483 @@
1
+ /**
2
+ * Trading Commands - Execute trades and manage orders
3
+ */
4
+
5
+ import { Command } from 'commander';
6
+ import { parseEther } from 'viem';
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import inquirer from 'inquirer';
10
+ import { AlphaFuturesClient } from '../../src';
11
+ import { formatUSD, formatTAO, formatPercentage } from '../../src/utils';
12
+ import { getClient, handleError, getMarketAddress } from '../utils/client';
13
+ import { confirmAction, validateDirection } from '../utils/prompts';
14
+ import { displayMarketSummary, calculatePnL } from '../utils/display';
15
+ import { openPositionCommon } from './shared/positionUtils';
16
+
17
+ export function tradingCommands(program: Command) {
18
+ const trade = program.command('trade').description('Execute trades');
19
+
20
+ // Market order command (redirects to position open)
21
+ trade
22
+ .command('market')
23
+ .description('Execute a market order (opens a position)')
24
+ .requiredOption('-a, --asset <asset>', 'Asset to trade')
25
+ .requiredOption('-s, --side <side>', 'Trade side: buy/long or sell/short')
26
+ .option(
27
+ '-z, --size <size>',
28
+ 'Position size in TAO (auto-calculated from margin × leverage if not provided)',
29
+ )
30
+ .option('-m, --margin <margin>', 'Margin amount in TAO')
31
+ .option('-l, --leverage <leverage>', 'Leverage (1-10x)', '3')
32
+ .option('-y, --yes', 'Skip confirmation')
33
+ .option('--sl, --stop-loss <price>', 'Stop loss price')
34
+ .option('--tp, --take-profit <price>', 'Take profit price')
35
+ .action(async (options) => {
36
+ try {
37
+ // Auto-calculate size if margin and leverage are provided
38
+ let size = options.size;
39
+ if (!size && options.margin) {
40
+ const marginValue = parseFloat(options.margin);
41
+ const leverageValue = parseFloat(options.leverage);
42
+ size = (marginValue * leverageValue).toString();
43
+ console.log(
44
+ chalk.gray(
45
+ `Auto-calculated position size: ${size} TAO (${marginValue} TAO margin × ${leverageValue}x leverage)`,
46
+ ),
47
+ );
48
+ } else if (!size && !options.margin) {
49
+ console.error(chalk.red('Error: Either --size or --margin must be provided'));
50
+ process.exit(1);
51
+ }
52
+
53
+ // Convert trade options to position options with strict validation
54
+ let direction: 'long' | 'short';
55
+ try {
56
+ direction = validateDirection(options.side);
57
+ } catch (error: any) {
58
+ console.error(chalk.red(`Error: ${error.message}`));
59
+ process.exit(1);
60
+ }
61
+
62
+ const positionOptions = {
63
+ asset: options.asset,
64
+ direction,
65
+ size: size,
66
+ leverage: parseFloat(options.leverage),
67
+ margin: options.margin,
68
+ skipConfirmation: options.yes,
69
+ stopLoss: options.stopLoss,
70
+ takeProfit: options.takeProfit,
71
+ };
72
+
73
+ const success = await openPositionCommon(positionOptions, program.opts());
74
+
75
+ if (success && (options.stopLoss || options.takeProfit)) {
76
+ console.log(chalk.yellow('\n⚠️ Stop loss and take profit orders coming soon'));
77
+ }
78
+ } catch (error) {
79
+ console.error(chalk.red('Market order failed'));
80
+ handleError(error, program.opts());
81
+ }
82
+ });
83
+
84
+ // Limit order command (placeholder for orderbook integration)
85
+ trade
86
+ .command('limit')
87
+ .description('Place a limit order')
88
+ .requiredOption('-a, --asset <asset>', 'Asset to trade')
89
+ .requiredOption('-s, --side <side>', 'Trade side: buy/long or sell/short')
90
+ .requiredOption('-p, --price <price>', 'Limit price')
91
+ .requiredOption('-z, --size <size>', 'Order size in USD')
92
+ .option('-m, --margin <margin>', 'Margin amount in TAO')
93
+ .option('-l, --leverage <leverage>', 'Leverage (1-10x)', '3')
94
+ .option('--post-only', 'Post-only order (maker only)')
95
+ .option('--ioc', 'Immediate or cancel')
96
+ .option('--fok', 'Fill or kill')
97
+ .action(async (options) => {
98
+ console.log(chalk.yellow('\n⚠️ Limit orders are coming soon!'));
99
+ console.log('The orderbook module is currently being integrated.');
100
+
101
+ // Show what the order would look like
102
+ const asset = options.asset.toUpperCase();
103
+
104
+ // Validate direction
105
+ let direction: 'long' | 'short';
106
+ try {
107
+ direction = validateDirection(options.side);
108
+ } catch (error: any) {
109
+ console.error(chalk.red(`Error: ${error.message}`));
110
+ return;
111
+ }
112
+
113
+ const price = parseEther(options.price);
114
+ const size = parseEther(options.size);
115
+ const leverage = parseFloat(options.leverage);
116
+
117
+ console.log(chalk.bold('\n📋 Limit Order Preview:'));
118
+ console.log(` Asset: ${chalk.cyan(asset)}`);
119
+ const isBuy = direction === 'long';
120
+ console.log(` Side: ${isBuy ? chalk.green('BUY') : chalk.red('SELL')}`);
121
+ console.log(` Price: ${formatUSD(price)}`);
122
+ console.log(` Size: ${formatUSD(size)}`);
123
+ console.log(` Leverage: ${leverage}x`);
124
+
125
+ if (options.postOnly) console.log(` Type: ${chalk.blue('Post-Only')}`);
126
+ if (options.ioc) console.log(` Type: ${chalk.orange('IOC')}`);
127
+ if (options.fok) console.log(` Type: ${chalk.red('FOK')}`);
128
+ });
129
+
130
+ // Quick trade command with interactive prompts
131
+ trade
132
+ .command('quick')
133
+ .description('Quick trade with interactive prompts')
134
+ .action(async () => {
135
+ try {
136
+ const client = await getClient(program.opts());
137
+ const alpha = client.getAlpha();
138
+ const userAddress = await client.getSignerAddress();
139
+
140
+ // Get available balance first
141
+ const available = await alpha.getAvailableMargin(userAddress);
142
+ console.log(chalk.cyan(`\nAvailable Balance: ${formatTAO(available)} TAO`));
143
+
144
+ // Interactive prompts
145
+ const answers = await inquirer.prompt([
146
+ {
147
+ type: 'input',
148
+ name: 'asset',
149
+ message: 'Asset to trade:',
150
+ default: 'ALPHA',
151
+ transformer: (input) => input.toUpperCase(),
152
+ filter: (input) => input.toUpperCase(),
153
+ },
154
+ {
155
+ type: 'list',
156
+ name: 'side',
157
+ message: 'Direction:',
158
+ choices: [
159
+ { name: chalk.green('Long (Buy) ↗'), value: 'long' },
160
+ { name: chalk.red('Short (Sell) ↘'), value: 'short' },
161
+ ],
162
+ },
163
+ {
164
+ type: 'input',
165
+ name: 'margin',
166
+ message: 'Margin amount (TAO):',
167
+ validate: (input: string) => {
168
+ const trimmed = input.trim();
169
+ const amount = parseFloat(trimmed);
170
+ if (isNaN(amount) || amount <= 0) {
171
+ return 'Please enter a valid amount greater than 0';
172
+ }
173
+ try {
174
+ if (parseEther(trimmed) > available) {
175
+ return `Insufficient balance (available: ${formatTAO(available)} TAO)`;
176
+ }
177
+ } catch {
178
+ return 'Please enter a valid number';
179
+ }
180
+ return true;
181
+ },
182
+ filter: (input: string) => input.trim(),
183
+ },
184
+ {
185
+ type: 'list',
186
+ name: 'leverage',
187
+ message: 'Leverage:',
188
+ choices: ['1x', '2x', '3x', '5x', '10x'],
189
+ default: '3x',
190
+ filter: (input) => parseFloat(input),
191
+ },
192
+ {
193
+ type: 'confirm',
194
+ name: 'confirm',
195
+ message: 'Execute trade?',
196
+ default: true,
197
+ },
198
+ ]);
199
+
200
+ if (!answers.confirm) {
201
+ console.log(chalk.yellow('Trade cancelled'));
202
+ return;
203
+ }
204
+
205
+ // Calculate position size
206
+ const marginAmount = parseEther(answers.margin);
207
+ const positionSize = (marginAmount * BigInt(Math.floor(answers.leverage * 100))) / 100n;
208
+
209
+ // Get current price
210
+ const currentPrice = await client.oracle.getPrice(answers.asset);
211
+
212
+ // Show final summary
213
+ console.log(chalk.bold('\n📊 Executing Trade:'));
214
+ console.log(
215
+ ` ${answers.side === 'long' ? chalk.green('LONG') : chalk.red('SHORT')} ${answers.asset}`,
216
+ );
217
+ console.log(` Size: ${formatUSD(positionSize)}`);
218
+ console.log(` Entry: ${formatUSD(currentPrice)}`);
219
+
220
+ const spinner = ora('Opening position...').start();
221
+
222
+ const marketAddress = getMarketAddress(asset);
223
+ const leverageBigInt = BigInt(Math.floor(answers.leverage * 100));
224
+ const hash = await alpha.openPosition(
225
+ marketAddress,
226
+ answers.side === 'long',
227
+ positionSize,
228
+ leverageBigInt,
229
+ );
230
+
231
+ const publicClient = client.getPublicClient();
232
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
233
+ spinner.succeed('Trade executed successfully!');
234
+
235
+ // Parse position opened event
236
+ const positionEvent = alpha.parsePositionOpenedEvent(receipt);
237
+ if (positionEvent) {
238
+ console.log(chalk.green(`\n✓ Position ID: ${positionEvent.positionId}`));
239
+ }
240
+ } catch (error) {
241
+ handleError(error, program.opts());
242
+ }
243
+ });
244
+
245
+ // Close all positions command
246
+ trade
247
+ .command('close-all')
248
+ .description('Close all open positions')
249
+ .option('-y, --yes', 'Skip confirmation')
250
+ .action(async (options) => {
251
+ const spinner = ora('Loading positions...').start();
252
+
253
+ try {
254
+ const client = await getClient(program.opts());
255
+ const alpha = client.getAlpha();
256
+ const userAddress = await client.getSignerAddress();
257
+
258
+ // Get all active positions
259
+ const positionIds = await alpha.getUserPositions(userAddress);
260
+ const positions = await Promise.all(positionIds.map((id) => alpha.getPosition(id)));
261
+
262
+ const activePositions = positions.filter((p) => p.size > 0n);
263
+
264
+ if (activePositions.length === 0) {
265
+ spinner.stop();
266
+ console.log(chalk.yellow('\nNo active positions to close'));
267
+ return;
268
+ }
269
+
270
+ spinner.stop();
271
+
272
+ // Calculate total P&L
273
+ let totalPnL = 0n;
274
+ console.log(chalk.bold(`\n🔒 Closing ${activePositions.length} positions:`));
275
+
276
+ const currentPrice = await client.oracle.getPrice('ALPHA'); // Placeholder asset
277
+
278
+ for (const pos of activePositions) {
279
+ const pnl = calculatePnL(pos, currentPrice, pos.size);
280
+
281
+ totalPnL += pnl;
282
+
283
+ console.log(
284
+ ` Position: ALPHA ${pos.isLong ? 'LONG' : 'SHORT'} - P&L: ${pnl >= 0 ? chalk.green('+' + formatUSD(pnl)) : chalk.red(formatUSD(pnl))}`,
285
+ );
286
+ }
287
+
288
+ console.log(
289
+ chalk.bold(
290
+ `\nTotal P&L: ${totalPnL >= 0 ? chalk.green('+' + formatUSD(totalPnL)) : chalk.red(formatUSD(totalPnL))}`,
291
+ ),
292
+ );
293
+
294
+ // Confirm
295
+ if (!options.yes) {
296
+ const confirmed = await confirmAction('Close all positions?');
297
+ if (!confirmed) {
298
+ console.log(chalk.yellow('Cancelled'));
299
+ return;
300
+ }
301
+ }
302
+
303
+ spinner.start('Closing positions...');
304
+
305
+ // Close all positions
306
+ const results = await Promise.allSettled(
307
+ activePositions.map((pos, index) => alpha.closePosition(positionIds[index], pos.size)),
308
+ );
309
+
310
+ spinner.stop();
311
+
312
+ // Report results
313
+ const successful = results.filter((r) => r.status === 'fulfilled').length;
314
+ const failed = results.filter((r) => r.status === 'rejected').length;
315
+
316
+ if (successful > 0) {
317
+ console.log(chalk.green(`\n✓ Successfully closed ${successful} positions`));
318
+ }
319
+ if (failed > 0) {
320
+ console.log(chalk.red(`✗ Failed to close ${failed} positions`));
321
+ }
322
+ } catch (error) {
323
+ spinner.fail('Failed to close positions');
324
+ handleError(error, program.opts());
325
+ }
326
+ });
327
+
328
+ // Trading calculator
329
+ trade
330
+ .command('calc')
331
+ .description('Trading calculator for position sizing and risk management')
332
+ .action(async () => {
333
+ try {
334
+ const answers = await inquirer.prompt([
335
+ {
336
+ type: 'input',
337
+ name: 'balance',
338
+ message: 'Account balance (TAO):',
339
+ validate: (input: string) => {
340
+ const value = parseFloat(input.trim());
341
+ if (isNaN(value)) {
342
+ return 'Please enter a valid number';
343
+ }
344
+ if (value <= 0) {
345
+ return 'Balance must be greater than 0';
346
+ }
347
+ return true;
348
+ },
349
+ filter: (input: string) => input.trim(),
350
+ },
351
+ {
352
+ type: 'input',
353
+ name: 'risk',
354
+ message: 'Risk per trade (%):',
355
+ default: '2',
356
+ validate: (input: string) => {
357
+ const value = parseFloat(input.trim());
358
+ if (isNaN(value)) {
359
+ return 'Please enter a valid number';
360
+ }
361
+ if (value <= 0 || value > 100) {
362
+ return 'Risk percentage must be between 0 and 100';
363
+ }
364
+ return true;
365
+ },
366
+ filter: (input: string) => input.trim(),
367
+ },
368
+ {
369
+ type: 'input',
370
+ name: 'entry',
371
+ message: 'Entry price ($):',
372
+ validate: (input: string) => {
373
+ const value = parseFloat(input.trim());
374
+ if (isNaN(value)) {
375
+ return 'Please enter a valid number';
376
+ }
377
+ if (value <= 0) {
378
+ return 'Entry price must be greater than 0';
379
+ }
380
+ return true;
381
+ },
382
+ filter: (input: string) => input.trim(),
383
+ },
384
+ {
385
+ type: 'input',
386
+ name: 'stop',
387
+ message: 'Stop loss price ($):',
388
+ validate: (input: string) => {
389
+ const value = parseFloat(input.trim());
390
+ if (isNaN(value)) {
391
+ return 'Please enter a valid number';
392
+ }
393
+ if (value <= 0) {
394
+ return 'Stop loss price must be greater than 0';
395
+ }
396
+ return true;
397
+ },
398
+ filter: (input: string) => input.trim(),
399
+ },
400
+ {
401
+ type: 'list',
402
+ name: 'leverage',
403
+ message: 'Leverage:',
404
+ choices: [
405
+ { name: '1x (No leverage)', value: '1' },
406
+ { name: '2x', value: '2' },
407
+ { name: '3x (Recommended)', value: '3' },
408
+ { name: '5x', value: '5' },
409
+ { name: '10x (High risk)', value: '10' },
410
+ ],
411
+ default: '3',
412
+ },
413
+ ]);
414
+
415
+ // Calculate position sizing
416
+ const balance = parseFloat(answers.balance);
417
+ const riskPercent = parseFloat(answers.risk) / 100;
418
+ const entry = parseFloat(answers.entry);
419
+ const stop = parseFloat(answers.stop);
420
+ const leverage = parseFloat(answers.leverage);
421
+
422
+ // Validate that entry and stop make sense
423
+ if (entry === stop) {
424
+ console.error(chalk.red('❌ Entry price and stop loss cannot be the same'));
425
+ return;
426
+ }
427
+
428
+ const isLong = stop < entry;
429
+ const riskPerUnit = Math.abs(entry - stop);
430
+ const riskAmount = balance * riskPercent;
431
+ const maxLoss = riskAmount;
432
+
433
+ // Validate risk per unit is reasonable
434
+ const riskPercentFromEntry = (riskPerUnit / entry) * 100;
435
+ if (riskPercentFromEntry > 50) {
436
+ console.log(
437
+ chalk.yellow(
438
+ `⚠️ Warning: Large price difference (${riskPercentFromEntry.toFixed(1)}% from entry price)`,
439
+ ),
440
+ );
441
+ }
442
+
443
+ // Position size calculation
444
+ const marginRequired = maxLoss / (riskPerUnit / entry);
445
+ const positionSize = marginRequired * leverage;
446
+
447
+ // Validate calculations
448
+ if (marginRequired <= 0 || positionSize <= 0) {
449
+ console.error(chalk.red('❌ Invalid calculation result. Please check your inputs.'));
450
+ return;
451
+ }
452
+
453
+ console.log(chalk.bold('\n📊 Position Calculation:'));
454
+ console.log(` Direction: ${isLong ? chalk.green('LONG') : chalk.red('SHORT')}`);
455
+ console.log(` Risk Amount: ${riskAmount.toFixed(2)} TAO (${answers.risk}%)`);
456
+ console.log(` Margin Required: ${marginRequired.toFixed(2)} TAO`);
457
+ console.log(` Position Size: $${positionSize.toFixed(2)}`);
458
+ console.log(` Risk per Unit: $${riskPerUnit.toFixed(2)}`);
459
+
460
+ // Calculate potential profit with different R multiples
461
+ console.log(chalk.bold('\n💰 Risk/Reward Scenarios:'));
462
+
463
+ const scenarios = [1, 2, 3, 5];
464
+ scenarios.forEach((r) => {
465
+ const target = isLong ? entry + riskPerUnit * r : entry - riskPerUnit * r;
466
+ const profit = riskAmount * r;
467
+ console.log(` ${r}R Target: $${target.toFixed(2)} → Profit: ${profit.toFixed(2)} TAO`);
468
+ });
469
+
470
+ // Liquidation info
471
+ const liquidationDistance = 0.2; // 20% for simplicity
472
+ const liquidationPrice = isLong
473
+ ? entry * (1 - liquidationDistance)
474
+ : entry * (1 + liquidationDistance);
475
+
476
+ console.log(chalk.bold('\n⚠️ Risk Management:'));
477
+ console.log(` Liquidation Price: ${chalk.red('$' + liquidationPrice.toFixed(2))}`);
478
+ console.log(` Max Leverage Safe: ${(1 / (riskPerUnit / entry)).toFixed(1)}x`);
479
+ } catch (error) {
480
+ handleError(error, program.opts());
481
+ }
482
+ });
483
+ }