hedgequantx 1.5.4 → 1.5.6
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/package.json +1 -1
- package/src/pages/algo/copy-trading.js +24 -16
- package/src/pages/algo/ui.js +17 -13
- package/src/services/rithmic/index.js +25 -8
package/package.json
CHANGED
|
@@ -136,33 +136,41 @@ const copyTradingMenu = async () => {
|
|
|
136
136
|
console.log();
|
|
137
137
|
console.log(chalk.cyan(' Step 5: Configure Parameters'));
|
|
138
138
|
|
|
139
|
-
const {
|
|
140
|
-
type: '
|
|
141
|
-
name: '
|
|
139
|
+
const { leadContractsInput } = await inquirer.prompt([{
|
|
140
|
+
type: 'input',
|
|
141
|
+
name: 'leadContractsInput',
|
|
142
142
|
message: 'Lead contracts:',
|
|
143
|
-
default: 1
|
|
143
|
+
default: '1',
|
|
144
|
+
validate: v => !isNaN(parseInt(v)) && parseInt(v) > 0 ? true : 'Enter a positive number'
|
|
144
145
|
}]);
|
|
146
|
+
const leadContracts = parseInt(leadContractsInput) || 1;
|
|
145
147
|
|
|
146
|
-
const {
|
|
147
|
-
type: '
|
|
148
|
-
name: '
|
|
148
|
+
const { followerContractsInput } = await inquirer.prompt([{
|
|
149
|
+
type: 'input',
|
|
150
|
+
name: 'followerContractsInput',
|
|
149
151
|
message: 'Follower contracts:',
|
|
150
|
-
default: leadContracts
|
|
152
|
+
default: String(leadContracts),
|
|
153
|
+
validate: v => !isNaN(parseInt(v)) && parseInt(v) > 0 ? true : 'Enter a positive number'
|
|
151
154
|
}]);
|
|
155
|
+
const followerContracts = parseInt(followerContractsInput) || leadContracts;
|
|
152
156
|
|
|
153
|
-
const {
|
|
154
|
-
type: '
|
|
155
|
-
name: '
|
|
157
|
+
const { dailyTargetInput } = await inquirer.prompt([{
|
|
158
|
+
type: 'input',
|
|
159
|
+
name: 'dailyTargetInput',
|
|
156
160
|
message: 'Daily target ($):',
|
|
157
|
-
default: 400
|
|
161
|
+
default: '400',
|
|
162
|
+
validate: v => !isNaN(parseInt(v)) && parseInt(v) > 0 ? true : 'Enter a positive number'
|
|
158
163
|
}]);
|
|
164
|
+
const dailyTarget = parseInt(dailyTargetInput) || 400;
|
|
159
165
|
|
|
160
|
-
const {
|
|
161
|
-
type: '
|
|
162
|
-
name: '
|
|
166
|
+
const { maxRiskInput } = await inquirer.prompt([{
|
|
167
|
+
type: 'input',
|
|
168
|
+
name: 'maxRiskInput',
|
|
163
169
|
message: 'Max risk ($):',
|
|
164
|
-
default: 200
|
|
170
|
+
default: '200',
|
|
171
|
+
validate: v => !isNaN(parseInt(v)) && parseInt(v) > 0 ? true : 'Enter a positive number'
|
|
165
172
|
}]);
|
|
173
|
+
const maxRisk = parseInt(maxRiskInput) || 200;
|
|
166
174
|
|
|
167
175
|
// Step 6: Privacy
|
|
168
176
|
const { showNames } = await inquirer.prompt([{
|
package/src/pages/algo/ui.js
CHANGED
|
@@ -146,11 +146,15 @@ class AlgoUI {
|
|
|
146
146
|
|
|
147
147
|
this._line(chalk.cyan(GT));
|
|
148
148
|
|
|
149
|
-
// Row 1: Account | Symbol
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
|
|
149
|
+
// Row 1: Account | Symbol (truncate long values)
|
|
150
|
+
const accName = (stats.accountName || 'N/A').substring(0, 35);
|
|
151
|
+
const symName = (stats.symbol || 'N/A').substring(0, 25);
|
|
152
|
+
const qtyStr = stats.contracts || '1/1';
|
|
153
|
+
|
|
154
|
+
const r1c1 = buildCell('Account', accName, chalk.cyan, colL);
|
|
155
|
+
const r1c2t = ` Symbol: ${chalk.yellow(symName)} Qty: ${chalk.cyan(qtyStr)}`;
|
|
156
|
+
const r1c2p = ` Symbol: ${symName} Qty: ${qtyStr}`;
|
|
157
|
+
row(r1c1.padded, r1c2t + pad(Math.max(0, colR - r1c2p.length)));
|
|
154
158
|
|
|
155
159
|
this._line(chalk.cyan(GM));
|
|
156
160
|
|
|
@@ -193,9 +197,9 @@ class AlgoUI {
|
|
|
193
197
|
this._line(chalk.cyan(BOX.V) + chalk.white(left) + ' '.repeat(midPad) + chalk.cyan(mid) + ' '.repeat(space - midPad - mid.length) + chalk.yellow(right) + chalk.cyan(BOX.V));
|
|
194
198
|
this._line(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
|
|
195
199
|
|
|
196
|
-
// Logs
|
|
197
|
-
// Take the last maxLogs entries
|
|
198
|
-
const visible = logs.slice(-maxLogs);
|
|
200
|
+
// Logs: newest at top, oldest at bottom
|
|
201
|
+
// Take the last maxLogs entries and reverse for display
|
|
202
|
+
const visible = logs.slice(-maxLogs).reverse();
|
|
199
203
|
|
|
200
204
|
if (visible.length === 0) {
|
|
201
205
|
this._line(chalk.cyan(BOX.V) + chalk.gray(fitToWidth(' Waiting for activity...', W)) + chalk.cyan(BOX.V));
|
|
@@ -203,17 +207,17 @@ class AlgoUI {
|
|
|
203
207
|
this._line(chalk.cyan(BOX.V) + ' '.repeat(W) + chalk.cyan(BOX.V));
|
|
204
208
|
}
|
|
205
209
|
} else {
|
|
206
|
-
//
|
|
207
|
-
for (let i = visible.length; i < maxLogs; i++) {
|
|
208
|
-
this._line(chalk.cyan(BOX.V) + ' '.repeat(W) + chalk.cyan(BOX.V));
|
|
209
|
-
}
|
|
210
|
-
// Then draw logs (oldest first, newest last/at bottom)
|
|
210
|
+
// Draw logs (newest first at top)
|
|
211
211
|
visible.forEach(log => {
|
|
212
212
|
const color = LOG_COLORS[log.type] || chalk.white;
|
|
213
213
|
const icon = LOG_ICONS[log.type] || LOG_ICONS.info;
|
|
214
214
|
const line = ` [${log.timestamp}] ${icon} ${log.message}`;
|
|
215
215
|
this._line(chalk.cyan(BOX.V) + color(fitToWidth(line, W)) + chalk.cyan(BOX.V));
|
|
216
216
|
});
|
|
217
|
+
// Pad remaining lines at bottom
|
|
218
|
+
for (let i = visible.length; i < maxLogs; i++) {
|
|
219
|
+
this._line(chalk.cyan(BOX.V) + ' '.repeat(W) + chalk.cyan(BOX.V));
|
|
220
|
+
}
|
|
217
221
|
}
|
|
218
222
|
|
|
219
223
|
// Bottom border
|
|
@@ -210,15 +210,32 @@ class RithmicService extends EventEmitter {
|
|
|
210
210
|
};
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
{ symbol: '
|
|
217
|
-
{ symbol: '
|
|
218
|
-
{ symbol: '
|
|
219
|
-
{ symbol: '
|
|
220
|
-
{ symbol: '
|
|
213
|
+
// All available contracts for Rithmic
|
|
214
|
+
_getAvailableContracts() {
|
|
215
|
+
return [
|
|
216
|
+
{ symbol: 'ESH5', name: 'E-mini S&P 500 Mar 2025', exchange: 'CME', group: 'Index' },
|
|
217
|
+
{ symbol: 'NQH5', name: 'E-mini NASDAQ-100 Mar 2025', exchange: 'CME', group: 'Index' },
|
|
218
|
+
{ symbol: 'MESH5', name: 'Micro E-mini S&P 500 Mar 2025', exchange: 'CME', group: 'Micro' },
|
|
219
|
+
{ symbol: 'MNQH5', name: 'Micro E-mini NASDAQ-100 Mar 2025', exchange: 'CME', group: 'Micro' },
|
|
220
|
+
{ symbol: 'MCLE5', name: 'Micro Crude Oil Mar 2025', exchange: 'NYMEX', group: 'Micro' },
|
|
221
|
+
{ symbol: 'MGCG5', name: 'Micro Gold Feb 2025', exchange: 'COMEX', group: 'Micro' },
|
|
222
|
+
{ symbol: 'CLH5', name: 'Crude Oil Mar 2025', exchange: 'NYMEX', group: 'Energy' },
|
|
223
|
+
{ symbol: 'GCG5', name: 'Gold Feb 2025', exchange: 'COMEX', group: 'Metals' },
|
|
224
|
+
{ symbol: 'SIH5', name: 'Silver Mar 2025', exchange: 'COMEX', group: 'Metals' },
|
|
225
|
+
{ symbol: 'RTYH5', name: 'E-mini Russell 2000 Mar 2025', exchange: 'CME', group: 'Index' },
|
|
226
|
+
{ symbol: 'YMH5', name: 'E-mini Dow Jones Mar 2025', exchange: 'CBOT', group: 'Index' },
|
|
227
|
+
{ symbol: 'ZBH5', name: '30-Year US Treasury Bond Mar 2025', exchange: 'CBOT', group: 'Bonds' },
|
|
228
|
+
{ symbol: 'ZNH5', name: '10-Year US Treasury Note Mar 2025', exchange: 'CBOT', group: 'Bonds' },
|
|
221
229
|
];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async getContracts() {
|
|
233
|
+
return { success: true, contracts: this._getAvailableContracts() };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async searchContracts(searchText) {
|
|
237
|
+
const contracts = this._getAvailableContracts();
|
|
238
|
+
if (!searchText) return contracts;
|
|
222
239
|
const search = searchText.toUpperCase();
|
|
223
240
|
return contracts.filter(c => c.symbol.includes(search) || c.name.toUpperCase().includes(search));
|
|
224
241
|
}
|