ctrader-ts 0.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/LICENSE +21 -0
- package/README.md +301 -0
- package/assets/banner.png +0 -0
- package/dist/bin/auth.d.ts +3 -0
- package/dist/bin/auth.d.ts.map +1 -0
- package/dist/bin/auth.js +193 -0
- package/dist/bin/auth.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +359 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/src/client.d.ts +310 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +507 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/config.d.ts +18 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +70 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/connect.d.ts +20 -0
- package/dist/src/connect.d.ts.map +1 -0
- package/dist/src/connect.js +36 -0
- package/dist/src/connect.js.map +1 -0
- package/dist/src/connection.d.ts +51 -0
- package/dist/src/connection.d.ts.map +1 -0
- package/dist/src/connection.js +292 -0
- package/dist/src/connection.js.map +1 -0
- package/dist/src/enums.d.ts +341 -0
- package/dist/src/enums.d.ts.map +1 -0
- package/dist/src/enums.js +369 -0
- package/dist/src/enums.js.map +1 -0
- package/dist/src/errors.d.ts +24 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +47 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/helpers.d.ts +28 -0
- package/dist/src/helpers.d.ts.map +1 -0
- package/dist/src/helpers.js +113 -0
- package/dist/src/helpers.js.map +1 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/modules/account.d.ts +67 -0
- package/dist/src/modules/account.d.ts.map +1 -0
- package/dist/src/modules/account.js +168 -0
- package/dist/src/modules/account.js.map +1 -0
- package/dist/src/modules/auth.d.ts +20 -0
- package/dist/src/modules/auth.d.ts.map +1 -0
- package/dist/src/modules/auth.js +43 -0
- package/dist/src/modules/auth.js.map +1 -0
- package/dist/src/modules/market.d.ts +53 -0
- package/dist/src/modules/market.d.ts.map +1 -0
- package/dist/src/modules/market.js +192 -0
- package/dist/src/modules/market.js.map +1 -0
- package/dist/src/modules/trading.d.ts +80 -0
- package/dist/src/modules/trading.d.ts.map +1 -0
- package/dist/src/modules/trading.js +150 -0
- package/dist/src/modules/trading.js.map +1 -0
- package/dist/src/symbol-cache.d.ts +14 -0
- package/dist/src/symbol-cache.d.ts.map +1 -0
- package/dist/src/symbol-cache.js +41 -0
- package/dist/src/symbol-cache.js.map +1 -0
- package/dist/src/types.d.ts +413 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 thecommandcat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="./assets/banner.png" alt="ctrader-ts" width="100%" />
|
|
4
|
+
|
|
5
|
+
<br />
|
|
6
|
+
<br />
|
|
7
|
+
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](https://nodejs.org/)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://help.ctrader.com/open-api/)
|
|
12
|
+
|
|
13
|
+
**Unofficial community TypeScript client for the cTrader Open API**
|
|
14
|
+
|
|
15
|
+
*Not affiliated with Spotware · Built by the community, for the community* 🤝
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What is this?
|
|
22
|
+
|
|
23
|
+
There's no official TypeScript SDK for the cTrader Open API. The API itself is a raw protobuf/WebSocket protocol — great for performance, painful to use. This is a community-built client that wraps the JSON WebSocket mode (port 5036) into something actually enjoyable:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const ct = await connect();
|
|
27
|
+
const pos = await ct.buy("EURUSD", { lots: 0.1, sl: { pips: 50 }, tp: { equity: 0.02 } });
|
|
28
|
+
await ct.close(pos.positionId);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
No manual auth flows, no volume unit conversions, no raw WebSocket management.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 🚀 Getting started
|
|
36
|
+
|
|
37
|
+
**Clone & link globally** (recommended — gets you the CLI too):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/thecommandcat/ctrader-ts
|
|
41
|
+
cd ctrader-ts
|
|
42
|
+
npm install && npm run build && npm link
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Or install as a library:**
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install ctrader-ts
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 🔐 Authenticate
|
|
52
|
+
|
|
53
|
+
Run the interactive OAuth wizard — walks you through the whole flow in 3 steps:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ctrader-ts auth
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
You'll need a cTrader Open API app. Create one at [openapi.ctrader.com/apps](https://openapi.ctrader.com/apps), grab your client ID + secret, and the wizard handles the rest. Credentials are saved to `~/.config/ctrader-ts/config.json`.
|
|
60
|
+
|
|
61
|
+
Prefer env vars? Those work too:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
CTRADER_CLIENT_ID=...
|
|
65
|
+
CTRADER_CLIENT_SECRET=...
|
|
66
|
+
CTRADER_ACCESS_TOKEN=...
|
|
67
|
+
CTRADER_ACCOUNT_ID=...
|
|
68
|
+
CTRADER_ENVIRONMENT=demo # or live
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 📦 Library
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { connect } from "ctrader-ts";
|
|
77
|
+
|
|
78
|
+
const ct = await connect(); // reads stored credentials, connects, authenticates
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 📊 Account state
|
|
82
|
+
|
|
83
|
+
Start here. One call, complete picture:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const state = await ct.getState();
|
|
87
|
+
// {
|
|
88
|
+
// balance, equity, usedMargin, freeMargin,
|
|
89
|
+
// marginLevel, unrealizedPnl,
|
|
90
|
+
// positions, orders, moneyDigits
|
|
91
|
+
// }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 💹 Trading
|
|
95
|
+
|
|
96
|
+
**Market orders** — execute immediately, return the opened `Position` directly:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const p1 = await ct.buy("EURUSD", { lots: 0.1 });
|
|
100
|
+
const p2 = await ct.buy("EURUSD", { lots: 0.05, sl: { pips: 50 }, tp: { pips: 100 } });
|
|
101
|
+
const p3 = await ct.sell("USDJPY", { lots: 0.1, sl: { dollars: 30 } });
|
|
102
|
+
const p4 = await ct.buy("XAUUSD", { lots: 0.01, sl: { equity: 0.02 } });
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Pending orders:**
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
await ct.buyLimit("EURUSD", { lots: 0.1, limitPrice: 1.0800 });
|
|
109
|
+
await ct.sellLimit("EURUSD", { lots: 0.1, limitPrice: 1.1200 });
|
|
110
|
+
await ct.buyStop("EURUSD", { lots: 0.1, stopPrice: 1.1050 });
|
|
111
|
+
await ct.sellStop("EURUSD", { lots: 0.1, stopPrice: 1.0950 });
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 🎯 SL/TP — three ways, zero math
|
|
115
|
+
|
|
116
|
+
No manual pip calculations. Every order accepts `sl` and `tp` in whichever unit makes sense:
|
|
117
|
+
|
|
118
|
+
| | Example | What it means |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| **Pips** | `{ pips: 50 }` | 50 pips from entry — symbol-aware (handles JPY, gold, etc.) |
|
|
121
|
+
| **Dollars** | `{ dollars: 25 }` | Lose/gain exactly $25 on this trade |
|
|
122
|
+
| **Equity %** | `{ equity: 0.02 }` | Risk 2% of your account equity |
|
|
123
|
+
|
|
124
|
+
The library fetches symbol details and current price automatically to do the conversion.
|
|
125
|
+
|
|
126
|
+
### 🔧 Position management
|
|
127
|
+
|
|
128
|
+
Positions use their real cTrader `positionId` — no invented ID system:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
// Move SL/TP at any time
|
|
132
|
+
await ct.modify(p1.positionId, { sl: { pips: 30 }, tp: { dollars: 50 } });
|
|
133
|
+
|
|
134
|
+
// Close — full or partial
|
|
135
|
+
await ct.close(p1.positionId);
|
|
136
|
+
await ct.close(p1.positionId, { lots: 0.02 }); // partial
|
|
137
|
+
|
|
138
|
+
// Nuke everything
|
|
139
|
+
await ct.closeSymbol("EURUSD");
|
|
140
|
+
await ct.closeAll();
|
|
141
|
+
|
|
142
|
+
// Cancel pending order
|
|
143
|
+
await ct.cancelOrder(orderId);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 📡 Live market data
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
// Stream bid/ask — returns an unsubscribe function
|
|
150
|
+
const stop = await ct.watchSpots(["EURUSD", "GBPUSD"], (price) => {
|
|
151
|
+
console.log(price.symbol, price.bidDecimal, price.askDecimal);
|
|
152
|
+
});
|
|
153
|
+
await stop(); // done
|
|
154
|
+
|
|
155
|
+
// Historical candles
|
|
156
|
+
const { trendbars } = await ct.getTrendbars("EURUSD", {
|
|
157
|
+
period: TrendbarPeriod.H1,
|
|
158
|
+
count: 100,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Raw tick data
|
|
162
|
+
const { ticks } = await ct.getTickData("EURUSD", {
|
|
163
|
+
type: QuoteType.BID,
|
|
164
|
+
fromTimestamp: Date.now() - 3_600_000,
|
|
165
|
+
toTimestamp: Date.now(),
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 🗂️ History & account data
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const { deals } = await ct.getDeals({ maxRows: 50 });
|
|
173
|
+
const { positions, orders } = await ct.getPositions();
|
|
174
|
+
const trader = await ct.getTrader();
|
|
175
|
+
const { margins } = await ct.getExpectedMargin("EURUSD", [0.1, 0.5, 1.0]);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### ⚡ Events
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
ct.onExecution((e) => console.log("fill:", e.executionType, e.position?.positionId));
|
|
182
|
+
ct.onOrderError((e) => console.error("order rejected:", e.errorCode));
|
|
183
|
+
ct.onTrailingSLChanged((e) => console.log("trailing SL moved to:", e.stopPrice));
|
|
184
|
+
ct.onMarginChanged((e) => console.log("margin updated:", e.usedMargin));
|
|
185
|
+
ct.onTokenInvalidated(() => console.warn("token expired — run ctrader-ts auth"));
|
|
186
|
+
ct.onClientDisconnect((e) => console.warn("server dropped connection:", e.reason));
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 🔩 Raw protocol access
|
|
190
|
+
|
|
191
|
+
Everything the high-level API doesn't expose is available via `ct.raw`:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
ct.raw.trading.marketRangeOrder({ ... });
|
|
195
|
+
ct.raw.account.getDynamicLeverage(leverageId);
|
|
196
|
+
ct.raw.market.subscribeLiveTrendbar(symbolId, TrendbarPeriod.M1);
|
|
197
|
+
ct.raw.auth.refreshToken(refreshToken);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### ⚙️ connect() options
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
const ct = await connect({
|
|
204
|
+
environment: "live", // override stored environment
|
|
205
|
+
accountId: 12345678, // override stored account
|
|
206
|
+
accessToken: "...", // override stored token
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 🖥️ CLI
|
|
213
|
+
|
|
214
|
+
Everything you can do in code, you can do from the terminal.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# 🔐 Auth
|
|
218
|
+
ctrader-ts auth
|
|
219
|
+
|
|
220
|
+
# 📊 Account
|
|
221
|
+
ctrader-ts state
|
|
222
|
+
ctrader-ts positions
|
|
223
|
+
|
|
224
|
+
# 💹 Trade
|
|
225
|
+
ctrader-ts buy EURUSD 0.1 --sl-pips 50 --tp-pips 100
|
|
226
|
+
ctrader-ts sell USDJPY 0.1 --sl-dollars 30
|
|
227
|
+
ctrader-ts buy XAUUSD 0.01 --sl-equity 0.02
|
|
228
|
+
|
|
229
|
+
# 📋 Pending orders
|
|
230
|
+
ctrader-ts buy-limit EURUSD 0.1 1.0800
|
|
231
|
+
ctrader-ts sell-limit EURUSD 0.1 1.1200
|
|
232
|
+
ctrader-ts buy-stop EURUSD 0.1 1.1050
|
|
233
|
+
|
|
234
|
+
# 🔧 Manage positions
|
|
235
|
+
ctrader-ts close 12345678 # full close
|
|
236
|
+
ctrader-ts close 12345678 --lots 0.05 # partial
|
|
237
|
+
ctrader-ts modify 12345678 --sl-pips 30 --tp-dollars 50
|
|
238
|
+
ctrader-ts close-symbol EURUSD
|
|
239
|
+
ctrader-ts close-all
|
|
240
|
+
ctrader-ts cancel 87654321
|
|
241
|
+
|
|
242
|
+
# 📡 Market data
|
|
243
|
+
ctrader-ts watch EURUSD GBPUSD # live prices, Ctrl+C to stop
|
|
244
|
+
ctrader-ts bars EURUSD H1 2024-01-01 2024-12-31
|
|
245
|
+
|
|
246
|
+
# 🗂️ History
|
|
247
|
+
ctrader-ts history --from 2024-01-01 --to 2024-12-31
|
|
248
|
+
|
|
249
|
+
# 🤖 Pipe-friendly JSON output
|
|
250
|
+
ctrader-ts state --json
|
|
251
|
+
ctrader-ts positions --json | jq '.positions[].positionId'
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 🤖 For AI agents
|
|
257
|
+
|
|
258
|
+
Built with AI agents in mind from the start:
|
|
259
|
+
|
|
260
|
+
- **`getState()` first** — gives a complete picture of the account before making any decisions
|
|
261
|
+
- **Human units everywhere** — `{ pips }`, `{ dollars }`, `{ equity }` means no internal encoding knowledge needed
|
|
262
|
+
- **Real position IDs** — every `buy()`/`sell()` returns the actual `positionId`, so modifying and closing are unambiguous
|
|
263
|
+
- **Typed errors** — agents can react to failures intelligently instead of just crashing
|
|
264
|
+
- **CLI with `--json`** — agents with shell access get structured output without a Node runtime in the loop
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
import { connect, CTraderError } from "ctrader-ts";
|
|
268
|
+
|
|
269
|
+
const ct = await connect();
|
|
270
|
+
const state = await ct.getState();
|
|
271
|
+
// reason about state.equity, state.positions, state.marginLevel...
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const pos = await ct.buy("EURUSD", { lots: 0.1, sl: { equity: 0.01 } });
|
|
275
|
+
console.log("opened", pos.positionId);
|
|
276
|
+
} catch (e) {
|
|
277
|
+
if (e instanceof CTraderError) {
|
|
278
|
+
if (e.isAuthError) { /* re-run auth */ }
|
|
279
|
+
if (e.isRateLimit) { /* wait e.retryAfter ms then retry */ }
|
|
280
|
+
if (e.isMaintenance) { /* server is down, try later */ }
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## 🔄 Reconnection
|
|
288
|
+
|
|
289
|
+
Drops happen. The library handles it automatically:
|
|
290
|
+
|
|
291
|
+
- Reconnects with exponential backoff (2s → 60s max)
|
|
292
|
+
- Re-authenticates after reconnect (app auth + account auth)
|
|
293
|
+
- Restores all active spot / depth / trendbar subscriptions
|
|
294
|
+
|
|
295
|
+
You don't need to do anything.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
MIT
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../bin/auth.ts"],"names":[],"mappings":""}
|
package/dist/bin/auth.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import { saveConfig, loadStoredConfig, getConfigPath, DEMO_ENDPOINT } from "../src/config.js";
|
|
4
|
+
import { CTraderConnection } from "../src/connection.js";
|
|
5
|
+
import { CTraderAuth } from "../src/modules/auth.js";
|
|
6
|
+
const OAUTH_TOKEN_URL = "https://openapi.ctrader.com/apps/token";
|
|
7
|
+
const REDIRECT_URI = "https://openapi.ctrader.com";
|
|
8
|
+
async function exchangeCodeForToken(code, clientId, clientSecret) {
|
|
9
|
+
const url = new URL(OAUTH_TOKEN_URL);
|
|
10
|
+
url.searchParams.set("grant_type", "authorization_code");
|
|
11
|
+
url.searchParams.set("code", code);
|
|
12
|
+
url.searchParams.set("redirect_uri", REDIRECT_URI);
|
|
13
|
+
url.searchParams.set("client_id", clientId);
|
|
14
|
+
url.searchParams.set("client_secret", clientSecret);
|
|
15
|
+
const res = await fetch(url.toString(), { headers: { Accept: "application/json" } });
|
|
16
|
+
if (!res.ok)
|
|
17
|
+
throw new Error(`HTTP ${res.status} from token endpoint`);
|
|
18
|
+
const body = (await res.json());
|
|
19
|
+
if (body["errorCode"])
|
|
20
|
+
throw new Error(`${body["errorCode"]}: ${body["description"]}`);
|
|
21
|
+
if (!body["accessToken"])
|
|
22
|
+
throw new Error("No accessToken in response");
|
|
23
|
+
return {
|
|
24
|
+
accessToken: body["accessToken"],
|
|
25
|
+
refreshToken: body["refreshToken"],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function buildAuthUrl(clientId) {
|
|
29
|
+
const url = new URL("https://id.ctrader.com/my/settings/openapi/grantingaccess/");
|
|
30
|
+
url.searchParams.set("client_id", clientId);
|
|
31
|
+
url.searchParams.set("redirect_uri", REDIRECT_URI);
|
|
32
|
+
url.searchParams.set("scope", "trading");
|
|
33
|
+
url.searchParams.set("product", "web");
|
|
34
|
+
return url.toString();
|
|
35
|
+
}
|
|
36
|
+
function extractCode(raw) {
|
|
37
|
+
const trimmed = raw.trim();
|
|
38
|
+
try {
|
|
39
|
+
return new URL(trimmed).searchParams.get("code");
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
if (trimmed.startsWith("code="))
|
|
43
|
+
return trimmed.slice(5);
|
|
44
|
+
if (trimmed && !trimmed.includes(" "))
|
|
45
|
+
return trimmed;
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function run() {
|
|
50
|
+
p.intro("ctrader-ts — setup");
|
|
51
|
+
const stored = loadStoredConfig();
|
|
52
|
+
// ─── Step 1: App credentials ──────────────────────────────────────────────
|
|
53
|
+
p.log.step("Step 1 of 3 — App credentials");
|
|
54
|
+
p.log.info("Go to https://openapi.ctrader.com/apps → select your app → View Credentials");
|
|
55
|
+
const clientId = await p.text({
|
|
56
|
+
message: "Client ID",
|
|
57
|
+
placeholder: "19544_xxxxxx",
|
|
58
|
+
...(stored.clientId ? { initialValue: stored.clientId } : {}),
|
|
59
|
+
validate: (v) => (v?.trim() ? undefined : "Required"),
|
|
60
|
+
});
|
|
61
|
+
if (p.isCancel(clientId)) {
|
|
62
|
+
p.cancel("Cancelled.");
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
const clientSecret = await p.password({
|
|
66
|
+
message: "Client Secret",
|
|
67
|
+
validate: (v) => (v?.trim() ? undefined : "Required"),
|
|
68
|
+
});
|
|
69
|
+
if (p.isCancel(clientSecret)) {
|
|
70
|
+
p.cancel("Cancelled.");
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
// ─── Step 2: Get access token ─────────────────────────────────────────────
|
|
74
|
+
p.log.step("Step 2 of 3 — Authorize");
|
|
75
|
+
let accessToken;
|
|
76
|
+
let refreshToken;
|
|
77
|
+
if (stored.accessToken && stored.refreshToken) {
|
|
78
|
+
const refresh = await p.confirm({
|
|
79
|
+
message: "You have a stored token. Re-authorize to get a fresh one?",
|
|
80
|
+
initialValue: false,
|
|
81
|
+
});
|
|
82
|
+
if (p.isCancel(refresh)) {
|
|
83
|
+
p.cancel("Cancelled.");
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
if (!refresh) {
|
|
87
|
+
accessToken = stored.accessToken;
|
|
88
|
+
refreshToken = stored.refreshToken;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
({ accessToken, refreshToken } = await doOAuthFlow(clientId, clientSecret));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
({ accessToken, refreshToken } = await doOAuthFlow(clientId, clientSecret));
|
|
96
|
+
}
|
|
97
|
+
// ─── Step 3: Pick account ─────────────────────────────────────────────────
|
|
98
|
+
p.log.step("Step 3 of 3 — Choose account");
|
|
99
|
+
const spinner = p.spinner();
|
|
100
|
+
spinner.start("Fetching accounts…");
|
|
101
|
+
const connection = new CTraderConnection({ endpoint: DEMO_ENDPOINT });
|
|
102
|
+
const auth = new CTraderAuth(connection);
|
|
103
|
+
let accounts;
|
|
104
|
+
try {
|
|
105
|
+
await connection.connect();
|
|
106
|
+
await auth.authenticateApp(clientId, clientSecret);
|
|
107
|
+
accounts = await auth.getAccountsByToken(accessToken);
|
|
108
|
+
connection.disconnect();
|
|
109
|
+
spinner.stop(`Found ${accounts.length} account${accounts.length !== 1 ? "s" : ""}`);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
connection.disconnect();
|
|
113
|
+
spinner.stop("Failed");
|
|
114
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
if (accounts.length === 0) {
|
|
118
|
+
p.log.error("No accounts linked to this token. Re-authorize and make sure to approve at least one account.");
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
const accountChoice = await p.select({
|
|
122
|
+
message: "Account",
|
|
123
|
+
options: accounts.map((a) => {
|
|
124
|
+
const type = a.isLive ? "live" : "demo";
|
|
125
|
+
const parts = [type];
|
|
126
|
+
if (a.traderLogin)
|
|
127
|
+
parts.push(`login ${a.traderLogin}`);
|
|
128
|
+
if (a.brokerTitleShort)
|
|
129
|
+
parts.push(a.brokerTitleShort);
|
|
130
|
+
return {
|
|
131
|
+
value: String(a.ctidTraderAccountId),
|
|
132
|
+
label: String(a.ctidTraderAccountId),
|
|
133
|
+
hint: parts.join(" · "),
|
|
134
|
+
};
|
|
135
|
+
}),
|
|
136
|
+
initialValue: stored.accountId ? String(stored.accountId) : undefined,
|
|
137
|
+
});
|
|
138
|
+
if (p.isCancel(accountChoice)) {
|
|
139
|
+
p.cancel("Cancelled.");
|
|
140
|
+
process.exit(0);
|
|
141
|
+
}
|
|
142
|
+
const chosen = accounts.find((a) => String(a.ctidTraderAccountId) === accountChoice);
|
|
143
|
+
const environment = chosen.isLive ? "live" : "demo";
|
|
144
|
+
// ─── Save ─────────────────────────────────────────────────────────────────
|
|
145
|
+
saveConfig({
|
|
146
|
+
clientId: clientId,
|
|
147
|
+
clientSecret: clientSecret,
|
|
148
|
+
accessToken,
|
|
149
|
+
refreshToken,
|
|
150
|
+
accountId: Number(accountChoice),
|
|
151
|
+
environment,
|
|
152
|
+
});
|
|
153
|
+
const login = chosen.traderLogin ? ` · login ${chosen.traderLogin}` : "";
|
|
154
|
+
p.outro(`Saved · account ${accountChoice} (${environment}${login}) → ${getConfigPath()}`);
|
|
155
|
+
}
|
|
156
|
+
async function doOAuthFlow(clientId, clientSecret) {
|
|
157
|
+
const authUrl = buildAuthUrl(clientId);
|
|
158
|
+
p.log.info("1. Make sure this redirect URI is registered in your app:");
|
|
159
|
+
p.log.info(` https://openapi.ctrader.com/apps → Edit → Redirect URIs → add: ${REDIRECT_URI}`);
|
|
160
|
+
p.log.info("");
|
|
161
|
+
p.log.info("2. Open this URL in your browser and log in with your cTrader ID:");
|
|
162
|
+
p.log.info(` ${authUrl}`);
|
|
163
|
+
p.log.info("");
|
|
164
|
+
p.log.info("3. After approving, you'll be redirected to openapi.ctrader.com.");
|
|
165
|
+
p.log.info(" Copy the full URL from the address bar and paste it below.");
|
|
166
|
+
const redirected = await p.text({
|
|
167
|
+
message: "Paste the redirect URL",
|
|
168
|
+
placeholder: "https://openapi.ctrader.com/?code=abc123xyz",
|
|
169
|
+
validate: (v) => (extractCode(v ?? "") ? undefined : "No code found — paste the full URL from your browser's address bar"),
|
|
170
|
+
});
|
|
171
|
+
if (p.isCancel(redirected)) {
|
|
172
|
+
p.cancel("Cancelled.");
|
|
173
|
+
process.exit(0);
|
|
174
|
+
}
|
|
175
|
+
const code = extractCode(redirected);
|
|
176
|
+
const spinner = p.spinner();
|
|
177
|
+
spinner.start("Exchanging code for access token…");
|
|
178
|
+
try {
|
|
179
|
+
const tokens = await exchangeCodeForToken(code, clientId, clientSecret);
|
|
180
|
+
spinner.stop("Access token obtained");
|
|
181
|
+
return tokens;
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
spinner.stop("Token exchange failed");
|
|
185
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
run().catch((err) => {
|
|
190
|
+
process.stderr.write(String(err) + "\n");
|
|
191
|
+
process.exit(1);
|
|
192
|
+
});
|
|
193
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../bin/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../cli/index.ts"],"names":[],"mappings":""}
|