@gbozee/ultimate 0.0.2-1 → 0.0.2-11
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/dist/index.d.ts +150 -50
- package/dist/index.js +603 -96
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
4
4
|
import PocketBase from 'pocketbase';
|
|
5
|
+
import { RecordModel } from 'pocketbase';
|
|
5
6
|
import { SocksProxyAgent } from 'socks-proxy-agent';
|
|
6
7
|
|
|
7
8
|
interface Position$1 {
|
|
8
9
|
id: number;
|
|
9
|
-
kind:
|
|
10
|
+
kind: "long" | "short";
|
|
10
11
|
entry: number;
|
|
11
12
|
symbol: string;
|
|
12
13
|
quantity: number;
|
|
@@ -16,6 +17,9 @@ interface Position$1 {
|
|
|
16
17
|
take_profit: number;
|
|
17
18
|
tp_quantity: number;
|
|
18
19
|
stop_quantity: number;
|
|
20
|
+
target_pnl?: number;
|
|
21
|
+
reduce_ratio?: number;
|
|
22
|
+
use_full?: boolean;
|
|
19
23
|
}
|
|
20
24
|
export interface Account {
|
|
21
25
|
id: number | string;
|
|
@@ -113,10 +117,11 @@ export interface BaseExchange {
|
|
|
113
117
|
price_places?: string;
|
|
114
118
|
decimal_places?: string;
|
|
115
119
|
}): Promise<any>;
|
|
120
|
+
setLeverage(payload: {
|
|
121
|
+
symbol: string;
|
|
122
|
+
leverage: number;
|
|
123
|
+
}): Promise<any>;
|
|
116
124
|
}
|
|
117
|
-
/**
|
|
118
|
-
* TypeScript type definitions for PocketBase collections and views
|
|
119
|
-
*/
|
|
120
125
|
export interface BaseSystemFields {
|
|
121
126
|
id: string;
|
|
122
127
|
created: string;
|
|
@@ -204,6 +209,16 @@ export interface PositionsView {
|
|
|
204
209
|
avg_liquidation?: any;
|
|
205
210
|
balance?: any;
|
|
206
211
|
}
|
|
212
|
+
export interface BullishMarket extends RecordModel {
|
|
213
|
+
id: string;
|
|
214
|
+
symbol: string;
|
|
215
|
+
risk: number;
|
|
216
|
+
}
|
|
217
|
+
export interface WindingDownMarket extends RecordModel {
|
|
218
|
+
id: string;
|
|
219
|
+
symbol: string;
|
|
220
|
+
risk_reward: number;
|
|
221
|
+
}
|
|
207
222
|
export type ExchangeType = {
|
|
208
223
|
owner: string;
|
|
209
224
|
exchange: string;
|
|
@@ -211,7 +226,19 @@ export type ExchangeType = {
|
|
|
211
226
|
export declare class AppDatabase {
|
|
212
227
|
private pb;
|
|
213
228
|
constructor(pb: PocketBase);
|
|
229
|
+
createOrUpdateLiveExchangeInstance(payload: {
|
|
230
|
+
account: ExchangeType;
|
|
231
|
+
symbol: string;
|
|
232
|
+
data?: any;
|
|
233
|
+
}): Promise<import("pocketbase").RecordModel>;
|
|
234
|
+
getLiveExchangeInstance(payload: {
|
|
235
|
+
account: ExchangeType;
|
|
236
|
+
symbol: string;
|
|
237
|
+
data?: any;
|
|
238
|
+
}): Promise<import("pocketbase").RecordModel>;
|
|
214
239
|
getProxyForAccount(account: ExchangeType): Promise<HttpsProxyAgent<`http://${string}`> | SocksProxyAgent>;
|
|
240
|
+
getAccounts(): Promise<ExchangeAccount[]>;
|
|
241
|
+
getAllSymbolConfigs(with_positions?: boolean): Promise<SymbolConfig[]>;
|
|
215
242
|
get_exchange_db_instance(account: ExchangeType): Promise<ExchangeAccount & {
|
|
216
243
|
expand?: {
|
|
217
244
|
proxy: Proxy$1;
|
|
@@ -297,11 +324,42 @@ export declare class AppDatabase {
|
|
|
297
324
|
symbol: string;
|
|
298
325
|
kind: "long" | "short";
|
|
299
326
|
account: ExchangeType;
|
|
300
|
-
}): Promise<
|
|
327
|
+
}): Promise<ScheduledTrade | null>;
|
|
301
328
|
getPositionStrategy(account: ExchangeType): Promise<{
|
|
302
329
|
strategy_instance: Strategy;
|
|
303
330
|
focus_account: ExchangeAccount;
|
|
304
331
|
}>;
|
|
332
|
+
createOrUpdateWindingDownMarket(symbol: string): Promise<import("pocketbase").RecordModel>;
|
|
333
|
+
getWindingDownMarkets(symbol?: string): Promise<WindingDownMarket[]>;
|
|
334
|
+
getBullishMarkets(options?: {
|
|
335
|
+
new_markets: Array<{
|
|
336
|
+
symbol: string;
|
|
337
|
+
percent: number;
|
|
338
|
+
}>;
|
|
339
|
+
totalRisk: number;
|
|
340
|
+
}): Promise<{
|
|
341
|
+
updated_bullish: BullishMarket[];
|
|
342
|
+
moved_to_winding: WindingDownMarket[];
|
|
343
|
+
}>;
|
|
344
|
+
updateSymbolConfigs(payload?: {
|
|
345
|
+
configs: Array<{
|
|
346
|
+
symbol: string;
|
|
347
|
+
support: number;
|
|
348
|
+
leverage: number;
|
|
349
|
+
min_size: number;
|
|
350
|
+
resistance: number;
|
|
351
|
+
price_places: string;
|
|
352
|
+
decimal_places: string;
|
|
353
|
+
}>;
|
|
354
|
+
}): Promise<{
|
|
355
|
+
updated: number;
|
|
356
|
+
created: number;
|
|
357
|
+
} | SymbolConfig[]>;
|
|
358
|
+
unwindSymbolFromDB(symbol: string): Promise<boolean>;
|
|
359
|
+
hasExistingPosition(symbol: string): Promise<import("pocketbase").RecordModel[]>;
|
|
360
|
+
removeSymbolFromUnwindingMarkets(symbol: string): Promise<boolean>;
|
|
361
|
+
removePosition(position: any): Promise<void>;
|
|
362
|
+
removePositionConfig(position: any): Promise<void>;
|
|
305
363
|
}
|
|
306
364
|
export interface CodeNode {
|
|
307
365
|
minimum_pnl: number;
|
|
@@ -347,6 +405,17 @@ declare class ExchangeAccount$1 {
|
|
|
347
405
|
exchange: BaseExchange;
|
|
348
406
|
app_db: AppDatabase;
|
|
349
407
|
});
|
|
408
|
+
/**
|
|
409
|
+
*In order to avoid rate limiting issues, we cache the live exchange
|
|
410
|
+
details for each symbol for an account in the database with an option
|
|
411
|
+
to refresh.
|
|
412
|
+
*/
|
|
413
|
+
getLiveExchangeInstance(payload: {
|
|
414
|
+
symbol: string;
|
|
415
|
+
refresh?: boolean;
|
|
416
|
+
price_places?: string;
|
|
417
|
+
decimal_places?: string;
|
|
418
|
+
}): Promise<import("pocketbase").RecordModel>;
|
|
350
419
|
getActiveAccount(symbol: string, full?: boolean): Promise<Account | {
|
|
351
420
|
liquidation: {
|
|
352
421
|
long: number;
|
|
@@ -361,6 +430,7 @@ declare class ExchangeAccount$1 {
|
|
|
361
430
|
kind?: "long" | "short";
|
|
362
431
|
update?: boolean;
|
|
363
432
|
as_view?: boolean;
|
|
433
|
+
leverage?: number;
|
|
364
434
|
}): Promise<(PositionsView & {
|
|
365
435
|
expand?: {
|
|
366
436
|
config: ScheduledTrade;
|
|
@@ -376,6 +446,11 @@ declare class ExchangeAccount$1 {
|
|
|
376
446
|
kind: "long" | "short";
|
|
377
447
|
update?: boolean;
|
|
378
448
|
}): Promise<import("pocketbase").RecordModel[]>;
|
|
449
|
+
toggleStopBuying(payload: {
|
|
450
|
+
symbol: string;
|
|
451
|
+
kind: "long" | "short";
|
|
452
|
+
should_stop?: boolean;
|
|
453
|
+
}): Promise<import("pocketbase").RecordModel>;
|
|
379
454
|
cancelOrders(payload: {
|
|
380
455
|
symbol: string;
|
|
381
456
|
kind: "long" | "short";
|
|
@@ -461,7 +536,7 @@ declare class ExchangeAccount$1 {
|
|
|
461
536
|
risk: number;
|
|
462
537
|
profit_percent?: number;
|
|
463
538
|
};
|
|
464
|
-
}): Promise<
|
|
539
|
+
}): Promise<ScheduledTrade>;
|
|
465
540
|
getCurrentPrice(symbol: string): Promise<any>;
|
|
466
541
|
getPositionStrategy(): Promise<{
|
|
467
542
|
strategy_instance: Strategy;
|
|
@@ -480,6 +555,48 @@ declare class ExchangeAccount$1 {
|
|
|
480
555
|
short: boolean;
|
|
481
556
|
};
|
|
482
557
|
}): Promise<any>;
|
|
558
|
+
generate_config_params(payload: {
|
|
559
|
+
entry: number;
|
|
560
|
+
stop: number;
|
|
561
|
+
risk_reward: number;
|
|
562
|
+
risk: number;
|
|
563
|
+
symbol: string;
|
|
564
|
+
}): Promise<{
|
|
565
|
+
place_stop: boolean;
|
|
566
|
+
profit_percent: number;
|
|
567
|
+
entry: number;
|
|
568
|
+
stop: number;
|
|
569
|
+
avg_size: any;
|
|
570
|
+
avg_entry: any;
|
|
571
|
+
risk_reward: number;
|
|
572
|
+
neg_pnl: any;
|
|
573
|
+
risk: number;
|
|
574
|
+
}>;
|
|
575
|
+
extrapolateShortConfig(payload: {
|
|
576
|
+
kind: "long" | "short";
|
|
577
|
+
symbol: string;
|
|
578
|
+
risk_reward?: number;
|
|
579
|
+
}): Promise<{
|
|
580
|
+
place_stop: boolean;
|
|
581
|
+
profit_percent: number;
|
|
582
|
+
entry: number;
|
|
583
|
+
stop: number;
|
|
584
|
+
avg_size: any;
|
|
585
|
+
avg_entry: any;
|
|
586
|
+
risk_reward: number;
|
|
587
|
+
neg_pnl: any;
|
|
588
|
+
risk: number;
|
|
589
|
+
}>;
|
|
590
|
+
triggerTradeFromConfig(payload: {
|
|
591
|
+
symbol: string;
|
|
592
|
+
kind: "long" | "short";
|
|
593
|
+
}): Promise<any>;
|
|
594
|
+
verifyStopLoss(payload: {
|
|
595
|
+
symbol: string;
|
|
596
|
+
kind: "long" | "short";
|
|
597
|
+
revert?: boolean;
|
|
598
|
+
}): Promise<import("pocketbase").RecordModel[]>;
|
|
599
|
+
windDownSymbol(symbol: string, risk_reward?: number): Promise<void>;
|
|
483
600
|
}
|
|
484
601
|
declare class App {
|
|
485
602
|
private app_db;
|
|
@@ -532,34 +649,6 @@ declare class App {
|
|
|
532
649
|
message?: undefined;
|
|
533
650
|
exchange_result?: undefined;
|
|
534
651
|
}>;
|
|
535
|
-
triggerTradeFromConfig(payload: {
|
|
536
|
-
account: ExchangeType;
|
|
537
|
-
symbol: string;
|
|
538
|
-
kind: "long" | "short";
|
|
539
|
-
}): Promise<any>;
|
|
540
|
-
toggleStopBuying(payload: {
|
|
541
|
-
account: ExchangeType;
|
|
542
|
-
symbol: string;
|
|
543
|
-
kind: "long" | "short";
|
|
544
|
-
should_stop?: boolean;
|
|
545
|
-
}): Promise<import("pocketbase").RecordModel>;
|
|
546
|
-
generate_config_params(exchange_account: ExchangeAccount$1, payload: {
|
|
547
|
-
entry: number;
|
|
548
|
-
stop: number;
|
|
549
|
-
risk_reward: number;
|
|
550
|
-
risk: number;
|
|
551
|
-
symbol: string;
|
|
552
|
-
}): Promise<{
|
|
553
|
-
place_stop: boolean;
|
|
554
|
-
profit_percent: number;
|
|
555
|
-
entry: number;
|
|
556
|
-
stop: number;
|
|
557
|
-
avg_size: any;
|
|
558
|
-
avg_entry: any;
|
|
559
|
-
risk_reward: number;
|
|
560
|
-
neg_pnl: any;
|
|
561
|
-
risk: number;
|
|
562
|
-
}>;
|
|
563
652
|
generateConfig(payload: {
|
|
564
653
|
account: ExchangeType;
|
|
565
654
|
symbol: string;
|
|
@@ -577,28 +666,39 @@ declare class App {
|
|
|
577
666
|
short_db_position: any;
|
|
578
667
|
balance: any;
|
|
579
668
|
}>;
|
|
580
|
-
extrapolateShortConfig(payload: {
|
|
581
|
-
account: ExchangeType;
|
|
582
|
-
kind: "long" | "short";
|
|
583
|
-
symbol: string;
|
|
584
|
-
risk_reward?: number;
|
|
585
|
-
}): Promise<PositionsView | {
|
|
586
|
-
place_stop: boolean;
|
|
587
|
-
profit_percent: number;
|
|
588
|
-
entry: number;
|
|
589
|
-
stop: number;
|
|
590
|
-
avg_size: any;
|
|
591
|
-
avg_entry: any;
|
|
592
|
-
risk_reward: number;
|
|
593
|
-
neg_pnl: any;
|
|
594
|
-
risk: number;
|
|
595
|
-
}>;
|
|
596
669
|
verifyStopLoss(payload: {
|
|
597
670
|
account: ExchangeType;
|
|
598
671
|
symbol: string;
|
|
599
672
|
kind: "long" | "short";
|
|
600
673
|
revert?: boolean;
|
|
601
674
|
}): Promise<import("pocketbase").RecordModel[]>;
|
|
675
|
+
updateTopMovers(payload?: {
|
|
676
|
+
new_markets: {
|
|
677
|
+
symbol: string;
|
|
678
|
+
percent: number;
|
|
679
|
+
}[];
|
|
680
|
+
totalRisk: number;
|
|
681
|
+
}): Promise<{
|
|
682
|
+
updated_bullish: BullishMarket[];
|
|
683
|
+
moved_to_winding: WindingDownMarket[];
|
|
684
|
+
}>;
|
|
685
|
+
getWindingDownMarkets(): Promise<WindingDownMarket[]>;
|
|
686
|
+
updateSymbolConfigs(payload: {
|
|
687
|
+
configs: {
|
|
688
|
+
symbol: string;
|
|
689
|
+
support: number;
|
|
690
|
+
leverage: number;
|
|
691
|
+
min_size: number;
|
|
692
|
+
resistance: number;
|
|
693
|
+
price_places: string;
|
|
694
|
+
decimal_places: string;
|
|
695
|
+
}[];
|
|
696
|
+
}): Promise<SymbolConfig[] | {
|
|
697
|
+
updated: number;
|
|
698
|
+
created: number;
|
|
699
|
+
}>;
|
|
700
|
+
updateAllAccountWithSymbols(with_positions?: boolean): Promise<void>;
|
|
701
|
+
windDownSymbol(symbol: string): Promise<boolean>;
|
|
602
702
|
}
|
|
603
703
|
export declare function initApp(payload: {
|
|
604
704
|
db: {
|
package/dist/index.js
CHANGED
|
@@ -31646,6 +31646,31 @@ class AppDatabase {
|
|
|
31646
31646
|
constructor(pb) {
|
|
31647
31647
|
this.pb = pb;
|
|
31648
31648
|
}
|
|
31649
|
+
async createOrUpdateLiveExchangeInstance(payload) {
|
|
31650
|
+
const result = await this.getLiveExchangeInstance(payload);
|
|
31651
|
+
if (result) {
|
|
31652
|
+
return await this.pb.collection("live_exchange_details").update(result.id, {
|
|
31653
|
+
data: payload.data
|
|
31654
|
+
});
|
|
31655
|
+
} else {
|
|
31656
|
+
const exchange_account = await this.get_exchange_db_instance(payload.account);
|
|
31657
|
+
return await this.pb.collection("live_exchange_details").create({
|
|
31658
|
+
symbol: payload.symbol,
|
|
31659
|
+
account: exchange_account.id,
|
|
31660
|
+
data: payload.data
|
|
31661
|
+
});
|
|
31662
|
+
}
|
|
31663
|
+
}
|
|
31664
|
+
async getLiveExchangeInstance(payload) {
|
|
31665
|
+
const result = await this.pb.collection("live_exchange_details").getFullList({
|
|
31666
|
+
filter: `account.owner:lower="${payload.account.owner.toLowerCase()}" && account.exchange:lower="${payload.account.exchange.toLowerCase()}" && symbol:lower="${payload.symbol.toLowerCase()}"`,
|
|
31667
|
+
expand: "account"
|
|
31668
|
+
});
|
|
31669
|
+
if (result.length > 0) {
|
|
31670
|
+
return result[0];
|
|
31671
|
+
}
|
|
31672
|
+
return null;
|
|
31673
|
+
}
|
|
31649
31674
|
async getProxyForAccount(account) {
|
|
31650
31675
|
const result = await this.get_exchange_db_instance(account);
|
|
31651
31676
|
if (result?.expand?.proxy) {
|
|
@@ -31660,6 +31685,22 @@ class AppDatabase {
|
|
|
31660
31685
|
}
|
|
31661
31686
|
return null;
|
|
31662
31687
|
}
|
|
31688
|
+
async getAccounts() {
|
|
31689
|
+
return await this.pb.collection("exchange_accounts").getFullList();
|
|
31690
|
+
}
|
|
31691
|
+
async getAllSymbolConfigs(with_positions) {
|
|
31692
|
+
if (with_positions) {
|
|
31693
|
+
const positions = await this.pb.collection("positions").getFullList({
|
|
31694
|
+
fields: `symbol`
|
|
31695
|
+
});
|
|
31696
|
+
const symbol_set = new Set(positions.map((p) => p.symbol));
|
|
31697
|
+
const filter = Array.from(symbol_set).map((s2) => `symbol:lower="${s2.toLowerCase()}"`).join(" || ");
|
|
31698
|
+
return await this.pb.collection("symbol_configs").getFullList({
|
|
31699
|
+
filter
|
|
31700
|
+
});
|
|
31701
|
+
}
|
|
31702
|
+
return await this.pb.collection("symbol_configs").getFullList();
|
|
31703
|
+
}
|
|
31663
31704
|
async get_exchange_db_instance(account) {
|
|
31664
31705
|
const result = await this.pb.collection("exchange_accounts").getFirstListItem(`owner="${account.owner}" && exchange="${account.exchange}"`, {
|
|
31665
31706
|
expand: "proxy"
|
|
@@ -31920,6 +31961,236 @@ class AppDatabase {
|
|
|
31920
31961
|
}
|
|
31921
31962
|
return null;
|
|
31922
31963
|
}
|
|
31964
|
+
async createOrUpdateWindingDownMarket(symbol) {
|
|
31965
|
+
const existing_winding_down_market = await this.pb.collection("winding_down_markets").getFullList({
|
|
31966
|
+
filter: `symbol:lower="${symbol.toLowerCase()}"`
|
|
31967
|
+
});
|
|
31968
|
+
if (existing_winding_down_market.length > 0) {
|
|
31969
|
+
return existing_winding_down_market[0];
|
|
31970
|
+
}
|
|
31971
|
+
return await this.pb.collection("winding_down_markets").create({ symbol, risk_reward: 199 });
|
|
31972
|
+
}
|
|
31973
|
+
async getWindingDownMarkets(symbol) {
|
|
31974
|
+
const result = await this.pb.collection("winding_down_markets").getFullList();
|
|
31975
|
+
if (symbol) {
|
|
31976
|
+
return result.filter((m) => m.symbol === symbol);
|
|
31977
|
+
}
|
|
31978
|
+
return result;
|
|
31979
|
+
}
|
|
31980
|
+
async getBullishMarkets(options) {
|
|
31981
|
+
if (!options) {
|
|
31982
|
+
return {
|
|
31983
|
+
updated_bullish: await this.pb.collection("bullish_markets").getFullList(),
|
|
31984
|
+
moved_to_winding: []
|
|
31985
|
+
};
|
|
31986
|
+
}
|
|
31987
|
+
const { new_markets, totalRisk } = options;
|
|
31988
|
+
const newMarketSymbols = new Set(new_markets.map((m) => m.symbol));
|
|
31989
|
+
console.log(`Processing ${new_markets.length} new top movers with total risk ${totalRisk}`);
|
|
31990
|
+
let currentBullish = [];
|
|
31991
|
+
try {
|
|
31992
|
+
currentBullish = await this.pb.collection("bullish_markets").getFullList();
|
|
31993
|
+
console.log(`Found ${currentBullish.length} existing bullish markets.`);
|
|
31994
|
+
} catch (error) {
|
|
31995
|
+
console.error("Error fetching current bullish markets:", error);
|
|
31996
|
+
currentBullish = [];
|
|
31997
|
+
}
|
|
31998
|
+
const currentBullishSymbols = new Set(currentBullish.map((m) => m.symbol));
|
|
31999
|
+
const moved_to_winding = [];
|
|
32000
|
+
const recordsToDeleteFromBullish = [];
|
|
32001
|
+
let windDownCreatedCount = 0;
|
|
32002
|
+
let currentWindingDown = [];
|
|
32003
|
+
let currentWindingDownSymbols = new Set;
|
|
32004
|
+
try {
|
|
32005
|
+
currentWindingDown = await this.getWindingDownMarkets();
|
|
32006
|
+
currentWindingDownSymbols = new Set(currentWindingDown.map((m) => m.symbol));
|
|
32007
|
+
console.log(`Found ${currentWindingDown.length} existing winding down markets.`);
|
|
32008
|
+
} catch (error) {
|
|
32009
|
+
console.error("Error fetching current winding down markets:", error);
|
|
32010
|
+
}
|
|
32011
|
+
console.log("Processing markets to potentially move to winding down...");
|
|
32012
|
+
for (const market of currentBullish) {
|
|
32013
|
+
if (!newMarketSymbols.has(market.symbol)) {
|
|
32014
|
+
console.log(`Processing ${market.symbol} for winding down.`);
|
|
32015
|
+
recordsToDeleteFromBullish.push(market.id);
|
|
32016
|
+
try {
|
|
32017
|
+
const windingDownRecord = await this.createOrUpdateWindingDownMarket(market.symbol);
|
|
32018
|
+
if (windingDownRecord) {
|
|
32019
|
+
moved_to_winding.push(windingDownRecord);
|
|
32020
|
+
windDownCreatedCount++;
|
|
32021
|
+
}
|
|
32022
|
+
} catch (windDownError) {
|
|
32023
|
+
console.error(`Error creating/updating winding down market for ${market.symbol} sequentially:`, windDownError);
|
|
32024
|
+
}
|
|
32025
|
+
}
|
|
32026
|
+
}
|
|
32027
|
+
console.log(`Finished processing potential winding down markets. ${windDownCreatedCount} processed.`);
|
|
32028
|
+
let deletedCount = 0;
|
|
32029
|
+
if (recordsToDeleteFromBullish.length > 0) {
|
|
32030
|
+
console.log(`Attempting to delete ${recordsToDeleteFromBullish.length} records sequentially from bullish_markets.`);
|
|
32031
|
+
for (const id of recordsToDeleteFromBullish) {
|
|
32032
|
+
try {
|
|
32033
|
+
await this.pb.collection("bullish_markets").delete(id);
|
|
32034
|
+
deletedCount++;
|
|
32035
|
+
} catch (deleteError) {
|
|
32036
|
+
console.error(`Error deleting bullish market record ${id} sequentially:`, deleteError);
|
|
32037
|
+
}
|
|
32038
|
+
}
|
|
32039
|
+
console.log(`Finished sequential deletion. Successfully deleted ${deletedCount} of ${recordsToDeleteFromBullish.length} records.`);
|
|
32040
|
+
}
|
|
32041
|
+
let updatedCount = 0;
|
|
32042
|
+
let createdMarkets = [];
|
|
32043
|
+
const recordsToDeleteFromWindingDown = [];
|
|
32044
|
+
if (totalRisk <= 0) {
|
|
32045
|
+
console.warn("Total percent movement is zero or negative. Cannot allocate risk.");
|
|
32046
|
+
} else {
|
|
32047
|
+
for (const newMarket of new_markets) {
|
|
32048
|
+
const calculatedRisk = newMarket.percent / totalRisk * totalRisk;
|
|
32049
|
+
if (currentWindingDownSymbols.has(newMarket.symbol)) {
|
|
32050
|
+
console.log(`Marking ${newMarket.symbol} for removal from winding down markets as it is now bullish.`);
|
|
32051
|
+
const windingDownRecord = currentWindingDown.find((w) => w.symbol === newMarket.symbol);
|
|
32052
|
+
if (windingDownRecord) {
|
|
32053
|
+
recordsToDeleteFromWindingDown.push(windingDownRecord.id);
|
|
32054
|
+
currentWindingDownSymbols.delete(newMarket.symbol);
|
|
32055
|
+
}
|
|
32056
|
+
}
|
|
32057
|
+
const existingMarket = currentBullish.find((m) => m.symbol === newMarket.symbol);
|
|
32058
|
+
if (existingMarket && !recordsToDeleteFromBullish.includes(existingMarket.id)) {
|
|
32059
|
+
if (existingMarket.risk !== calculatedRisk) {
|
|
32060
|
+
console.log(`Updating existing bullish market sequentially: ${newMarket.symbol} with risk ${calculatedRisk}`);
|
|
32061
|
+
try {
|
|
32062
|
+
await this.pb.collection("bullish_markets").update(existingMarket.id, {
|
|
32063
|
+
risk: calculatedRisk
|
|
32064
|
+
});
|
|
32065
|
+
updatedCount++;
|
|
32066
|
+
} catch (updateError) {
|
|
32067
|
+
console.error(`Error updating bullish market ${newMarket.symbol} sequentially:`, updateError);
|
|
32068
|
+
}
|
|
32069
|
+
}
|
|
32070
|
+
} else if (!currentBullishSymbols.has(newMarket.symbol)) {
|
|
32071
|
+
console.log(`Creating new bullish market sequentially: ${newMarket.symbol} with risk ${calculatedRisk}`);
|
|
32072
|
+
try {
|
|
32073
|
+
const createdMarket = await this.pb.collection("bullish_markets").create({
|
|
32074
|
+
symbol: newMarket.symbol,
|
|
32075
|
+
risk: calculatedRisk
|
|
32076
|
+
});
|
|
32077
|
+
createdMarkets.push(createdMarket);
|
|
32078
|
+
} catch (createError) {
|
|
32079
|
+
console.error(`Error creating bullish market ${newMarket.symbol} sequentially:`, createError);
|
|
32080
|
+
}
|
|
32081
|
+
}
|
|
32082
|
+
}
|
|
32083
|
+
}
|
|
32084
|
+
let windingDownDeletedCount = 0;
|
|
32085
|
+
if (recordsToDeleteFromWindingDown.length > 0) {
|
|
32086
|
+
console.log(`Attempting to delete ${recordsToDeleteFromWindingDown.length} records sequentially from winding_down_markets.`);
|
|
32087
|
+
for (const id of recordsToDeleteFromWindingDown) {
|
|
32088
|
+
try {
|
|
32089
|
+
await this.pb.collection("winding_down_markets").delete(id);
|
|
32090
|
+
windingDownDeletedCount++;
|
|
32091
|
+
} catch (deleteError) {
|
|
32092
|
+
console.error(`Error deleting winding down market record ${id} sequentially:`, deleteError);
|
|
32093
|
+
}
|
|
32094
|
+
}
|
|
32095
|
+
console.log(`Finished sequential deletion from winding down. Successfully deleted ${windingDownDeletedCount} of ${recordsToDeleteFromWindingDown.length} records.`);
|
|
32096
|
+
}
|
|
32097
|
+
console.log(`Successfully updated ${updatedCount} bullish markets sequentially.`);
|
|
32098
|
+
console.log(`Successfully created ${createdMarkets.length} bullish markets sequentially.`);
|
|
32099
|
+
const updated_bullish = await this.pb.collection("bullish_markets").getFullList();
|
|
32100
|
+
return { updated_bullish, moved_to_winding };
|
|
32101
|
+
}
|
|
32102
|
+
async updateSymbolConfigs(payload) {
|
|
32103
|
+
if (!payload || !payload.configs) {
|
|
32104
|
+
console.log("No payload provided. Fetching all symbol configs...");
|
|
32105
|
+
try {
|
|
32106
|
+
const allConfigs = await this.pb.collection("symbol_configs").getFullList();
|
|
32107
|
+
console.log(`Found ${allConfigs.length} symbol configs.`);
|
|
32108
|
+
return allConfigs;
|
|
32109
|
+
} catch (error) {
|
|
32110
|
+
console.error("Error fetching all symbol configs:", error);
|
|
32111
|
+
throw error;
|
|
32112
|
+
}
|
|
32113
|
+
}
|
|
32114
|
+
console.log(`Processing ${payload.configs.length} symbol config updates/creates...`);
|
|
32115
|
+
let existingConfigsMap = new Map;
|
|
32116
|
+
try {
|
|
32117
|
+
const existingConfigsList = await this.pb.collection("symbol_configs").getFullList();
|
|
32118
|
+
existingConfigsMap = new Map(existingConfigsList.map((c) => [c.symbol.toLowerCase(), c]));
|
|
32119
|
+
console.log(`Found ${existingConfigsMap.size} existing symbol configs in DB.`);
|
|
32120
|
+
} catch (error) {
|
|
32121
|
+
console.error("Error fetching existing symbol configs:", error);
|
|
32122
|
+
}
|
|
32123
|
+
let updatedCount = 0;
|
|
32124
|
+
let createdCount = 0;
|
|
32125
|
+
for (const config of payload.configs) {
|
|
32126
|
+
const lowerCaseSymbol = config.symbol.toLowerCase();
|
|
32127
|
+
const existingConfig = existingConfigsMap.get(lowerCaseSymbol);
|
|
32128
|
+
const dataToUpsert = {
|
|
32129
|
+
symbol: config.symbol,
|
|
32130
|
+
support: config.support,
|
|
32131
|
+
resistance: config.resistance,
|
|
32132
|
+
leverage: config.leverage,
|
|
32133
|
+
min_size: config.min_size,
|
|
32134
|
+
price_places: config.price_places,
|
|
32135
|
+
decimal_places: config.decimal_places
|
|
32136
|
+
};
|
|
32137
|
+
if (existingConfig) {
|
|
32138
|
+
try {
|
|
32139
|
+
if (Object.keys(dataToUpsert).some((key) => dataToUpsert[key] !== existingConfig[key])) {
|
|
32140
|
+
console.log(`Updating symbol config for: ${config.symbol}`);
|
|
32141
|
+
await this.pb.collection("symbol_configs").update(existingConfig.id, dataToUpsert);
|
|
32142
|
+
updatedCount++;
|
|
32143
|
+
} else {
|
|
32144
|
+
console.log(`No changes detected for symbol config: ${config.symbol}. Skipping update.`);
|
|
32145
|
+
}
|
|
32146
|
+
} catch (updateError) {
|
|
32147
|
+
console.error(`Error updating symbol config for ${config.symbol}:`, updateError);
|
|
32148
|
+
}
|
|
32149
|
+
} else {
|
|
32150
|
+
try {
|
|
32151
|
+
console.log(`Creating new symbol config for: ${config.symbol}`);
|
|
32152
|
+
await this.pb.collection("symbol_configs").create(dataToUpsert);
|
|
32153
|
+
createdCount++;
|
|
32154
|
+
} catch (createError) {
|
|
32155
|
+
console.error(`Error creating symbol config for ${config.symbol}:`, createError);
|
|
32156
|
+
}
|
|
32157
|
+
}
|
|
32158
|
+
}
|
|
32159
|
+
console.log(`Finished processing symbol configs. Updated: ${updatedCount}, Created: ${createdCount}`);
|
|
32160
|
+
return { updated: updatedCount, created: createdCount };
|
|
32161
|
+
}
|
|
32162
|
+
async unwindSymbolFromDB(symbol) {
|
|
32163
|
+
const symbol_configs = await this.pb.collection("symbol_configs").getFullList({
|
|
32164
|
+
filter: `symbol:lower="${symbol.toLowerCase()}"`
|
|
32165
|
+
});
|
|
32166
|
+
if (symbol_configs.length > 0) {
|
|
32167
|
+
await this.pb.collection("symbol_configs").delete(symbol_configs[0].id);
|
|
32168
|
+
}
|
|
32169
|
+
return await this.removeSymbolFromUnwindingMarkets(symbol);
|
|
32170
|
+
}
|
|
32171
|
+
async hasExistingPosition(symbol) {
|
|
32172
|
+
const result = await this.pb.collection("positions").getFullList({
|
|
32173
|
+
filter: `symbol:lower="${symbol.toLowerCase()}"`,
|
|
32174
|
+
expand: "account"
|
|
32175
|
+
});
|
|
32176
|
+
return result;
|
|
32177
|
+
}
|
|
32178
|
+
async removeSymbolFromUnwindingMarkets(symbol) {
|
|
32179
|
+
const result = await this.pb.collection("winding_down_markets").getFullList({
|
|
32180
|
+
filter: `symbol:lower="${symbol.toLowerCase()}"`
|
|
32181
|
+
});
|
|
32182
|
+
if (result.length > 0) {
|
|
32183
|
+
await this.pb.collection("winding_down_markets").delete(result[0].id);
|
|
32184
|
+
return true;
|
|
32185
|
+
}
|
|
32186
|
+
return false;
|
|
32187
|
+
}
|
|
32188
|
+
async removePosition(position) {
|
|
32189
|
+
await this.pb.collection("positions").delete(position.id);
|
|
32190
|
+
}
|
|
32191
|
+
async removePositionConfig(position) {
|
|
32192
|
+
await this.pb.collection("scheduled_trades").delete(position.config);
|
|
32193
|
+
}
|
|
31923
32194
|
}
|
|
31924
32195
|
|
|
31925
32196
|
// src/exchanges/binance.ts
|
|
@@ -32079,9 +32350,7 @@ class Signal {
|
|
|
32079
32350
|
support: kind === "long" ? _stop_loss : this.support
|
|
32080
32351
|
};
|
|
32081
32352
|
const instance = new Signal(derivedConfig);
|
|
32082
|
-
const ll = this.resistance?.toString().split(".")[0].length || 5;
|
|
32083
32353
|
if (kind === "short") {
|
|
32084
|
-
console.log("llll", ll);
|
|
32085
32354
|
}
|
|
32086
32355
|
let result = instance.get_bulk_trade_zones({ current_price, kind });
|
|
32087
32356
|
return result;
|
|
@@ -32316,7 +32585,6 @@ class Signal {
|
|
|
32316
32585
|
entries = Array.from({ length: Math.floor(this.risk_reward) + 1 }, (_, x) => to_f(margin_range[1] * Math.pow(1 + percent_change, x), this.price_places));
|
|
32317
32586
|
}
|
|
32318
32587
|
if (Math.min(...entries) < this.to_f(current_price) && this.to_f(current_price) < Math.max(...entries)) {
|
|
32319
|
-
console.log("found: ", entries, "current: ", current_price);
|
|
32320
32588
|
return entries.sort((a, b) => a - b);
|
|
32321
32589
|
}
|
|
32322
32590
|
if (remaining_zones.length > 0) {
|
|
@@ -32510,7 +32778,6 @@ class Signal {
|
|
|
32510
32778
|
});
|
|
32511
32779
|
let total_orders = limit_trades.concat(market_trades);
|
|
32512
32780
|
if (kind === "short") {
|
|
32513
|
-
console.log("raw_total", total_orders);
|
|
32514
32781
|
}
|
|
32515
32782
|
if (this.minimum_size && total_orders.length > 0) {
|
|
32516
32783
|
let payload = total_orders;
|
|
@@ -33490,6 +33757,9 @@ class BinanceExchange {
|
|
|
33490
33757
|
decimal_places: payload.decimal_places
|
|
33491
33758
|
});
|
|
33492
33759
|
}
|
|
33760
|
+
async setLeverage(payload) {
|
|
33761
|
+
return await this.client.setLeverage(payload);
|
|
33762
|
+
}
|
|
33493
33763
|
}
|
|
33494
33764
|
|
|
33495
33765
|
// src/exchanges/bybit.ts
|
|
@@ -34094,6 +34364,14 @@ class BybitExchange {
|
|
|
34094
34364
|
decimal_places: payload.decimal_places
|
|
34095
34365
|
});
|
|
34096
34366
|
}
|
|
34367
|
+
async setLeverage(payload) {
|
|
34368
|
+
return await this.client.setLeverage({
|
|
34369
|
+
category: "linear",
|
|
34370
|
+
symbol: payload.symbol,
|
|
34371
|
+
buyLeverage: payload.leverage.toString(),
|
|
34372
|
+
sellLeverage: payload.leverage.toString()
|
|
34373
|
+
});
|
|
34374
|
+
}
|
|
34097
34375
|
}
|
|
34098
34376
|
|
|
34099
34377
|
// src/helpers/accounts.ts
|
|
@@ -34546,8 +34824,6 @@ function get_app_config_and_max_size(config, payload) {
|
|
|
34546
34824
|
price_places: app_config.price_places,
|
|
34547
34825
|
decimal_places: app_config.decimal_places
|
|
34548
34826
|
});
|
|
34549
|
-
console.log("app_config", app_config);
|
|
34550
|
-
console.log("initialResult", initialResult);
|
|
34551
34827
|
const max_size = initialResult[0]?.avg_size;
|
|
34552
34828
|
return {
|
|
34553
34829
|
app_config,
|
|
@@ -34753,9 +35029,33 @@ class ExchangeAccount {
|
|
|
34753
35029
|
this.exchange = options.exchange;
|
|
34754
35030
|
this.app_db = options.app_db;
|
|
34755
35031
|
}
|
|
35032
|
+
async getLiveExchangeInstance(payload) {
|
|
35033
|
+
const result = await this.app_db.getLiveExchangeInstance({
|
|
35034
|
+
account: this.instance,
|
|
35035
|
+
symbol: payload.symbol
|
|
35036
|
+
});
|
|
35037
|
+
if (payload.refresh || !result) {
|
|
35038
|
+
const data = await this.exchange.getExchangeAccountInfo(this.instance, payload.symbol);
|
|
35039
|
+
if (payload.price_places) {
|
|
35040
|
+
data.config.price_places = payload.price_places;
|
|
35041
|
+
}
|
|
35042
|
+
if (payload.decimal_places) {
|
|
35043
|
+
data.config.decimal_places = payload.decimal_places;
|
|
35044
|
+
}
|
|
35045
|
+
return await this.app_db.createOrUpdateLiveExchangeInstance({
|
|
35046
|
+
account: this.instance,
|
|
35047
|
+
symbol: payload.symbol,
|
|
35048
|
+
data
|
|
35049
|
+
});
|
|
35050
|
+
}
|
|
35051
|
+
return result;
|
|
35052
|
+
}
|
|
34756
35053
|
async getActiveAccount(symbol, full) {
|
|
34757
35054
|
const symbol_config = await this.app_db.getSymbolConfigFromDB(symbol);
|
|
34758
|
-
const
|
|
35055
|
+
const live_exchange_instance = await this.getLiveExchangeInstance({
|
|
35056
|
+
symbol
|
|
35057
|
+
});
|
|
35058
|
+
const raw_active_account = live_exchange_instance.data;
|
|
34759
35059
|
const _all = get_active_accounts({
|
|
34760
35060
|
active_account: raw_active_account,
|
|
34761
35061
|
symbol_config
|
|
@@ -34779,6 +35079,9 @@ class ExchangeAccount {
|
|
|
34779
35079
|
return db_positions2;
|
|
34780
35080
|
}
|
|
34781
35081
|
const active_account = await this.getActiveAccount(symbol);
|
|
35082
|
+
if (options.leverage) {
|
|
35083
|
+
await this.exchange.setLeverage({ symbol, leverage: options.leverage });
|
|
35084
|
+
}
|
|
34782
35085
|
const db_positions = await this.app_db.createOrUpdatePositions(this.instance, {
|
|
34783
35086
|
symbol,
|
|
34784
35087
|
long_position: active_account.position.long,
|
|
@@ -34809,15 +35112,42 @@ class ExchangeAccount {
|
|
|
34809
35112
|
kind
|
|
34810
35113
|
}, all_orders);
|
|
34811
35114
|
}
|
|
35115
|
+
async toggleStopBuying(payload) {
|
|
35116
|
+
const { symbol, kind, should_stop = false } = payload;
|
|
35117
|
+
const position2 = await this.syncAccount({
|
|
35118
|
+
symbol,
|
|
35119
|
+
kind
|
|
35120
|
+
});
|
|
35121
|
+
if (should_stop) {
|
|
35122
|
+
return await this.app_db.update_db_position(position2, {
|
|
35123
|
+
config: null
|
|
35124
|
+
});
|
|
35125
|
+
}
|
|
35126
|
+
if (!position2.config) {
|
|
35127
|
+
const config = await this.getPositionConfig({
|
|
35128
|
+
symbol,
|
|
35129
|
+
kind
|
|
35130
|
+
});
|
|
35131
|
+
if (config) {
|
|
35132
|
+
return await this.app_db.update_db_position(position2, {
|
|
35133
|
+
config: config.id
|
|
35134
|
+
});
|
|
35135
|
+
}
|
|
35136
|
+
}
|
|
35137
|
+
}
|
|
34812
35138
|
async cancelOrders(payload) {
|
|
34813
35139
|
const { symbol, kind, price: _price, all, stop } = payload;
|
|
34814
35140
|
let price = _price || 0;
|
|
35141
|
+
await this.getLiveExchangeInstance({
|
|
35142
|
+
symbol,
|
|
35143
|
+
refresh: true
|
|
35144
|
+
});
|
|
35145
|
+
await this.syncOrders({
|
|
35146
|
+
symbol,
|
|
35147
|
+
kind,
|
|
35148
|
+
update: true
|
|
35149
|
+
});
|
|
34815
35150
|
if (all) {
|
|
34816
|
-
await this.syncOrders({
|
|
34817
|
-
symbol,
|
|
34818
|
-
kind,
|
|
34819
|
-
update: true
|
|
34820
|
-
});
|
|
34821
35151
|
} else {
|
|
34822
35152
|
if (!price) {
|
|
34823
35153
|
const position2 = await this.syncAccount({
|
|
@@ -34828,7 +35158,7 @@ class ExchangeAccount {
|
|
|
34828
35158
|
price = position2?.take_profit || 0;
|
|
34829
35159
|
}
|
|
34830
35160
|
}
|
|
34831
|
-
|
|
35161
|
+
let result = await this.app_db.cancelOrders({
|
|
34832
35162
|
cancelExchangeOrders: this.cancelExchangeOrders.bind(this),
|
|
34833
35163
|
all,
|
|
34834
35164
|
kind,
|
|
@@ -34837,6 +35167,7 @@ class ExchangeAccount {
|
|
|
34837
35167
|
price,
|
|
34838
35168
|
stop
|
|
34839
35169
|
});
|
|
35170
|
+
return result;
|
|
34840
35171
|
}
|
|
34841
35172
|
async cancelExchangeOrders(payload) {
|
|
34842
35173
|
return this.exchange.cancelOrders(payload);
|
|
@@ -34955,7 +35286,7 @@ class ExchangeAccount {
|
|
|
34955
35286
|
symbol: payload.symbol
|
|
34956
35287
|
}, false);
|
|
34957
35288
|
if (action === "place_limit_orders" && payload.place) {
|
|
34958
|
-
|
|
35289
|
+
let result = await this.exchange.bulkPlaceLimitOrders({
|
|
34959
35290
|
orders: trades.map((x) => ({
|
|
34960
35291
|
entry: x.entry,
|
|
34961
35292
|
quantity: x.quantity
|
|
@@ -34965,9 +35296,14 @@ class ExchangeAccount {
|
|
|
34965
35296
|
symbol: payload.symbol,
|
|
34966
35297
|
place: payload.place
|
|
34967
35298
|
});
|
|
35299
|
+
await this.getLiveExchangeInstance({
|
|
35300
|
+
symbol: payload.symbol,
|
|
35301
|
+
refresh: true
|
|
35302
|
+
});
|
|
35303
|
+
return result;
|
|
34968
35304
|
}
|
|
34969
35305
|
if (action === "place_stop_orders" && payload.place) {
|
|
34970
|
-
|
|
35306
|
+
let result = await this.exchange.placeStopOrders({
|
|
34971
35307
|
symbol: payload.symbol,
|
|
34972
35308
|
quantity: trades[0].avg_size,
|
|
34973
35309
|
kind: app_config.kind,
|
|
@@ -34976,6 +35312,11 @@ class ExchangeAccount {
|
|
|
34976
35312
|
decimal_places: app_config.decimal_places,
|
|
34977
35313
|
place: true
|
|
34978
35314
|
});
|
|
35315
|
+
await this.getLiveExchangeInstance({
|
|
35316
|
+
symbol: payload.symbol,
|
|
35317
|
+
refresh: true
|
|
35318
|
+
});
|
|
35319
|
+
return result;
|
|
34979
35320
|
}
|
|
34980
35321
|
return {
|
|
34981
35322
|
entry_orders,
|
|
@@ -35079,6 +35420,188 @@ class ExchangeAccount {
|
|
|
35079
35420
|
short
|
|
35080
35421
|
}, accountInfo, trigger, this.exchange);
|
|
35081
35422
|
}
|
|
35423
|
+
async generate_config_params(payload) {
|
|
35424
|
+
const { entry, stop, risk_reward, risk, symbol } = payload;
|
|
35425
|
+
const app_config = await this.buildAppConfig({
|
|
35426
|
+
entry,
|
|
35427
|
+
stop,
|
|
35428
|
+
risk_reward,
|
|
35429
|
+
risk,
|
|
35430
|
+
symbol
|
|
35431
|
+
});
|
|
35432
|
+
let config = generate_config_params(app_config, {
|
|
35433
|
+
entry,
|
|
35434
|
+
stop,
|
|
35435
|
+
risk_reward,
|
|
35436
|
+
risk,
|
|
35437
|
+
symbol
|
|
35438
|
+
});
|
|
35439
|
+
return { ...config, place_stop: false, profit_percent: 0 };
|
|
35440
|
+
}
|
|
35441
|
+
async extrapolateShortConfig(payload) {
|
|
35442
|
+
const { symbol, risk_reward = 199, kind } = payload;
|
|
35443
|
+
let reverse_kind = kind === "long" ? "short" : "long";
|
|
35444
|
+
const position2 = await this.syncAccount({
|
|
35445
|
+
symbol,
|
|
35446
|
+
kind: reverse_kind,
|
|
35447
|
+
as_view: true
|
|
35448
|
+
});
|
|
35449
|
+
if (position2) {
|
|
35450
|
+
return await this.generate_config_params({
|
|
35451
|
+
entry: position2.next_order || position2.avg_liquidation,
|
|
35452
|
+
stop: position2.take_profit,
|
|
35453
|
+
risk_reward,
|
|
35454
|
+
risk: position2.target_pnl,
|
|
35455
|
+
symbol
|
|
35456
|
+
});
|
|
35457
|
+
}
|
|
35458
|
+
return null;
|
|
35459
|
+
}
|
|
35460
|
+
async triggerTradeFromConfig(payload) {
|
|
35461
|
+
const position2 = await this.syncAccount({
|
|
35462
|
+
symbol: payload.symbol,
|
|
35463
|
+
kind: payload.kind
|
|
35464
|
+
});
|
|
35465
|
+
if (position2?.config) {
|
|
35466
|
+
const config = position2.expand.config;
|
|
35467
|
+
return await this.placeSharedOrder("place_limit_orders", {
|
|
35468
|
+
symbol: payload.symbol,
|
|
35469
|
+
entry: config.entry,
|
|
35470
|
+
stop: config.stop,
|
|
35471
|
+
risk_reward: config.risk_reward,
|
|
35472
|
+
risk: config.risk,
|
|
35473
|
+
place: true
|
|
35474
|
+
});
|
|
35475
|
+
}
|
|
35476
|
+
}
|
|
35477
|
+
async verifyStopLoss(payload) {
|
|
35478
|
+
const { symbol, kind, revert } = payload;
|
|
35479
|
+
await this.syncOrders({
|
|
35480
|
+
symbol,
|
|
35481
|
+
kind,
|
|
35482
|
+
update: true
|
|
35483
|
+
});
|
|
35484
|
+
let original = null;
|
|
35485
|
+
if (revert) {
|
|
35486
|
+
original = await this.getOriginalPlannedStop({
|
|
35487
|
+
symbol,
|
|
35488
|
+
kind
|
|
35489
|
+
});
|
|
35490
|
+
}
|
|
35491
|
+
const position2 = await this.syncAccount({
|
|
35492
|
+
symbol,
|
|
35493
|
+
kind,
|
|
35494
|
+
as_view: true
|
|
35495
|
+
});
|
|
35496
|
+
if (original && position2?.stop_loss && original.quantity != position2.stop_loss.quantity) {
|
|
35497
|
+
const opposite_kind = kind === "long" ? "short" : "long";
|
|
35498
|
+
await this.cancelOrders({
|
|
35499
|
+
symbol,
|
|
35500
|
+
kind: opposite_kind,
|
|
35501
|
+
stop: true
|
|
35502
|
+
});
|
|
35503
|
+
return await this.syncOrders({
|
|
35504
|
+
symbol,
|
|
35505
|
+
kind,
|
|
35506
|
+
update: true
|
|
35507
|
+
});
|
|
35508
|
+
}
|
|
35509
|
+
if (true) {
|
|
35510
|
+
const opposite_kind = kind === "long" ? "short" : "long";
|
|
35511
|
+
await this.syncOrders({
|
|
35512
|
+
symbol,
|
|
35513
|
+
kind: opposite_kind,
|
|
35514
|
+
update: true
|
|
35515
|
+
});
|
|
35516
|
+
await this.cancelOrders({
|
|
35517
|
+
symbol,
|
|
35518
|
+
kind: opposite_kind,
|
|
35519
|
+
stop: true
|
|
35520
|
+
});
|
|
35521
|
+
await this.syncReduceClosePosition(symbol, {
|
|
35522
|
+
kind: opposite_kind
|
|
35523
|
+
});
|
|
35524
|
+
await this.syncOrders({
|
|
35525
|
+
symbol,
|
|
35526
|
+
kind,
|
|
35527
|
+
update: true
|
|
35528
|
+
});
|
|
35529
|
+
}
|
|
35530
|
+
}
|
|
35531
|
+
async windDownSymbol(symbol, risk_reward = 199) {
|
|
35532
|
+
const positions = await this.syncAccount({
|
|
35533
|
+
symbol,
|
|
35534
|
+
as_view: true
|
|
35535
|
+
});
|
|
35536
|
+
let long_position = positions.find((x) => x.kind === "long");
|
|
35537
|
+
let short_position = positions.find((x) => x.kind === "short");
|
|
35538
|
+
if (long_position && long_position.quantity > 0) {
|
|
35539
|
+
console.log("Start to wind down the long position");
|
|
35540
|
+
let config = long_position?.expand?.config;
|
|
35541
|
+
if (!config && long_position.config) {
|
|
35542
|
+
config = await this.getPositionConfig({
|
|
35543
|
+
symbol,
|
|
35544
|
+
kind: "long"
|
|
35545
|
+
});
|
|
35546
|
+
}
|
|
35547
|
+
if (config) {
|
|
35548
|
+
console.log("cancelling any existing open orders for the long position");
|
|
35549
|
+
await this.cancelOrders({
|
|
35550
|
+
symbol,
|
|
35551
|
+
kind: "long",
|
|
35552
|
+
price: long_position.entry
|
|
35553
|
+
});
|
|
35554
|
+
console.log("updating the long position target_pnl");
|
|
35555
|
+
console.log("toggling the stop buying for the long position");
|
|
35556
|
+
await this.toggleStopBuying({
|
|
35557
|
+
symbol,
|
|
35558
|
+
kind: "long",
|
|
35559
|
+
should_stop: true
|
|
35560
|
+
});
|
|
35561
|
+
}
|
|
35562
|
+
const new_config = await this.extrapolateShortConfig({
|
|
35563
|
+
symbol,
|
|
35564
|
+
kind: "short",
|
|
35565
|
+
risk_reward
|
|
35566
|
+
});
|
|
35567
|
+
const short_config = await this.getPositionConfig({
|
|
35568
|
+
symbol,
|
|
35569
|
+
kind: "short"
|
|
35570
|
+
});
|
|
35571
|
+
if (new_config && short_config && (short_config.entry !== new_config.entry || short_config.stop !== new_config.stop || short_config.risk !== new_config.risk)) {
|
|
35572
|
+
console.log("updating short position");
|
|
35573
|
+
short_position = await this.app_db.update_db_position(short_position, {
|
|
35574
|
+
reduce_ratio: 0.95
|
|
35575
|
+
});
|
|
35576
|
+
console.log("Updating the short position config");
|
|
35577
|
+
await this.getPositionConfig({
|
|
35578
|
+
symbol,
|
|
35579
|
+
kind: "short",
|
|
35580
|
+
params: {
|
|
35581
|
+
entry: new_config.entry,
|
|
35582
|
+
stop: new_config.stop,
|
|
35583
|
+
risk_reward,
|
|
35584
|
+
risk: new_config.risk,
|
|
35585
|
+
profit_percent: 1
|
|
35586
|
+
}
|
|
35587
|
+
});
|
|
35588
|
+
console.log("placing the short trade based off config values");
|
|
35589
|
+
await this.triggerTradeFromConfig({
|
|
35590
|
+
symbol,
|
|
35591
|
+
kind: "short"
|
|
35592
|
+
});
|
|
35593
|
+
console.log("updating the stop loss for the short position from the long");
|
|
35594
|
+
await this.verifyStopLoss({
|
|
35595
|
+
symbol,
|
|
35596
|
+
kind: "short"
|
|
35597
|
+
});
|
|
35598
|
+
}
|
|
35599
|
+
}
|
|
35600
|
+
if (long_position && long_position.quantity === 0 && short_position && short_position.quantity == 0) {
|
|
35601
|
+
this.app_db.removePosition(long_position);
|
|
35602
|
+
this.app_db.removePosition(short_position);
|
|
35603
|
+
}
|
|
35604
|
+
}
|
|
35082
35605
|
}
|
|
35083
35606
|
function getExchangeKlass(exchange) {
|
|
35084
35607
|
const func = exchange === "binance" ? BinanceExchange : BybitExchange;
|
|
@@ -35171,66 +35694,6 @@ class App {
|
|
|
35171
35694
|
stop: payload.stop
|
|
35172
35695
|
});
|
|
35173
35696
|
}
|
|
35174
|
-
async triggerTradeFromConfig(payload) {
|
|
35175
|
-
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
35176
|
-
const position2 = await exchange_account.syncAccount({
|
|
35177
|
-
symbol: payload.symbol,
|
|
35178
|
-
kind: payload.kind
|
|
35179
|
-
});
|
|
35180
|
-
if (position2?.config) {
|
|
35181
|
-
const config = position2.expand.config;
|
|
35182
|
-
return await exchange_account.placeSharedOrder("place_limit_orders", {
|
|
35183
|
-
symbol: payload.symbol,
|
|
35184
|
-
entry: config.entry,
|
|
35185
|
-
stop: config.stop,
|
|
35186
|
-
risk_reward: config.risk_reward,
|
|
35187
|
-
risk: config.risk,
|
|
35188
|
-
place: true
|
|
35189
|
-
});
|
|
35190
|
-
}
|
|
35191
|
-
}
|
|
35192
|
-
async toggleStopBuying(payload) {
|
|
35193
|
-
const { symbol, kind, should_stop = false } = payload;
|
|
35194
|
-
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
35195
|
-
const position2 = await exchange_account.syncAccount({
|
|
35196
|
-
symbol,
|
|
35197
|
-
kind
|
|
35198
|
-
});
|
|
35199
|
-
if (should_stop) {
|
|
35200
|
-
return await this.app_db.update_db_position(position2, {
|
|
35201
|
-
config: null
|
|
35202
|
-
});
|
|
35203
|
-
}
|
|
35204
|
-
if (!position2.config) {
|
|
35205
|
-
const config = await exchange_account.getPositionConfig({
|
|
35206
|
-
symbol,
|
|
35207
|
-
kind
|
|
35208
|
-
});
|
|
35209
|
-
if (config) {
|
|
35210
|
-
return await this.app_db.update_db_position(position2, {
|
|
35211
|
-
config: config.id
|
|
35212
|
-
});
|
|
35213
|
-
}
|
|
35214
|
-
}
|
|
35215
|
-
}
|
|
35216
|
-
async generate_config_params(exchange_account, payload) {
|
|
35217
|
-
const { entry, stop, risk_reward, risk, symbol } = payload;
|
|
35218
|
-
const app_config = await exchange_account.buildAppConfig({
|
|
35219
|
-
entry,
|
|
35220
|
-
stop,
|
|
35221
|
-
risk_reward,
|
|
35222
|
-
risk,
|
|
35223
|
-
symbol
|
|
35224
|
-
});
|
|
35225
|
-
let config = generate_config_params(app_config, {
|
|
35226
|
-
entry,
|
|
35227
|
-
stop,
|
|
35228
|
-
risk_reward,
|
|
35229
|
-
risk,
|
|
35230
|
-
symbol
|
|
35231
|
-
});
|
|
35232
|
-
return { ...config, place_stop: false, profit_percent: 0 };
|
|
35233
|
-
}
|
|
35234
35697
|
async generateConfig(payload) {
|
|
35235
35698
|
const { symbol, kind } = payload;
|
|
35236
35699
|
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
@@ -35272,7 +35735,7 @@ class App {
|
|
|
35272
35735
|
if (!risk_factor) {
|
|
35273
35736
|
return null;
|
|
35274
35737
|
}
|
|
35275
|
-
let config = await
|
|
35738
|
+
let config = await exchange_account.generate_config_params({
|
|
35276
35739
|
entry,
|
|
35277
35740
|
stop,
|
|
35278
35741
|
risk_reward: config_instance.risk_reward,
|
|
@@ -35350,26 +35813,6 @@ class App {
|
|
|
35350
35813
|
balance: active_account.usd_balance
|
|
35351
35814
|
};
|
|
35352
35815
|
}
|
|
35353
|
-
async extrapolateShortConfig(payload) {
|
|
35354
|
-
const { symbol, risk_reward = 199, kind } = payload;
|
|
35355
|
-
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
35356
|
-
let reverse_kind = kind === "long" ? "short" : "long";
|
|
35357
|
-
const position2 = await exchange_account.syncAccount({
|
|
35358
|
-
symbol,
|
|
35359
|
-
kind: reverse_kind,
|
|
35360
|
-
as_view: true
|
|
35361
|
-
});
|
|
35362
|
-
if (position2) {
|
|
35363
|
-
return await this.generate_config_params(exchange_account, {
|
|
35364
|
-
entry: position2.next_order || position2.avg_liquidation,
|
|
35365
|
-
stop: position2.take_profit,
|
|
35366
|
-
risk_reward,
|
|
35367
|
-
risk: position2.target_pnl,
|
|
35368
|
-
symbol
|
|
35369
|
-
});
|
|
35370
|
-
}
|
|
35371
|
-
return position2;
|
|
35372
|
-
}
|
|
35373
35816
|
async verifyStopLoss(payload) {
|
|
35374
35817
|
const { account, symbol, kind, revert } = payload;
|
|
35375
35818
|
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
@@ -35426,6 +35869,70 @@ class App {
|
|
|
35426
35869
|
});
|
|
35427
35870
|
}
|
|
35428
35871
|
}
|
|
35872
|
+
async updateTopMovers(payload) {
|
|
35873
|
+
return await this.app_db.getBullishMarkets(payload);
|
|
35874
|
+
}
|
|
35875
|
+
async getWindingDownMarkets() {
|
|
35876
|
+
return await this.app_db.getWindingDownMarkets();
|
|
35877
|
+
}
|
|
35878
|
+
async updateSymbolConfigs(payload) {
|
|
35879
|
+
return await this.app_db.updateSymbolConfigs(payload);
|
|
35880
|
+
}
|
|
35881
|
+
async updateAllAccountWithSymbols(with_positions) {
|
|
35882
|
+
const [accounts, symbol_configs] = await Promise.all([
|
|
35883
|
+
this.app_db.getAccounts(),
|
|
35884
|
+
this.app_db.getAllSymbolConfigs(with_positions)
|
|
35885
|
+
]);
|
|
35886
|
+
for (const account of accounts) {
|
|
35887
|
+
for (const symbol_config of symbol_configs) {
|
|
35888
|
+
const exchange_account = await this.getExchangeAccount(account);
|
|
35889
|
+
await exchange_account.getLiveExchangeInstance({
|
|
35890
|
+
symbol: symbol_config.symbol,
|
|
35891
|
+
price_places: symbol_config.price_places,
|
|
35892
|
+
decimal_places: symbol_config.decimal_places,
|
|
35893
|
+
refresh: true
|
|
35894
|
+
});
|
|
35895
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
35896
|
+
}
|
|
35897
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
35898
|
+
}
|
|
35899
|
+
}
|
|
35900
|
+
async windDownSymbol(symbol) {
|
|
35901
|
+
let winding_instance = await this.app_db.getWindingDownMarkets(symbol);
|
|
35902
|
+
if (winding_instance && winding_instance.length > 0) {
|
|
35903
|
+
winding_instance = winding_instance[0];
|
|
35904
|
+
}
|
|
35905
|
+
if (!winding_instance || winding_instance.length === 0) {
|
|
35906
|
+
return true;
|
|
35907
|
+
}
|
|
35908
|
+
const positions = await this.app_db.hasExistingPosition(symbol);
|
|
35909
|
+
if (positions.length === 0) {
|
|
35910
|
+
return this.app_db.unwindSymbolFromDB(symbol);
|
|
35911
|
+
}
|
|
35912
|
+
const unique_instances = new Set(positions.map((x) => `${x.symbol}-${x.expand.account.owner}-${x.expand.account.exchange}`));
|
|
35913
|
+
let position_pairs = [];
|
|
35914
|
+
for (const instance of unique_instances) {
|
|
35915
|
+
const pair = positions.filter((x) => `${x.symbol}-${x.expand.account.owner}-${x.expand.account.exchange}` === instance && x.quantity === 0);
|
|
35916
|
+
if (pair.length === 2) {
|
|
35917
|
+
position_pairs = position_pairs.concat(pair);
|
|
35918
|
+
}
|
|
35919
|
+
}
|
|
35920
|
+
const not_paired_positions = positions.filter((x) => !position_pairs.map((p) => p.id).includes(x.id) && x.kind === "long");
|
|
35921
|
+
console.log("not_paired_positions", not_paired_positions.map((x) => `${x.symbol} - ${x.expand.account.owner} - ${x.expand.account.exchange}`));
|
|
35922
|
+
if (position_pairs.length > 0) {
|
|
35923
|
+
console.log("removing position pairs");
|
|
35924
|
+
for (const pair of position_pairs) {
|
|
35925
|
+
await this.app_db.removePosition(pair);
|
|
35926
|
+
}
|
|
35927
|
+
}
|
|
35928
|
+
if (not_paired_positions.length > 0) {
|
|
35929
|
+
console.log("winding down not paired positions");
|
|
35930
|
+
for (const pair of not_paired_positions) {
|
|
35931
|
+
const exchange_account = await this.getExchangeAccount(pair.expand.account);
|
|
35932
|
+
await exchange_account.windDownSymbol(pair.symbol, winding_instance?.risk_reward || 199);
|
|
35933
|
+
}
|
|
35934
|
+
}
|
|
35935
|
+
}
|
|
35429
35936
|
}
|
|
35430
35937
|
async function initApp(payload) {
|
|
35431
35938
|
const pb = await initPocketBaseClient(payload.db);
|