@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.
Files changed (3) hide show
  1. package/dist/index.d.ts +150 -50
  2. package/dist/index.js +603 -96
  3. 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: string;
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<import("pocketbase").RecordModel>;
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<import("pocketbase").RecordModel>;
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 raw_active_account = await this.exchange.getExchangeAccountInfo(this.instance, symbol);
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
- return this.app_db.cancelOrders({
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
- return await this.exchange.bulkPlaceLimitOrders({
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
- return await this.exchange.placeStopOrders({
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 this.generate_config_params(exchange_account, {
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);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-1",
4
+ "version": "0.0.2-11",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",