@gbozee/ultimate 0.0.2-40 → 0.0.2-43

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 CHANGED
@@ -377,6 +377,22 @@ export declare class AppDatabase {
377
377
  order_id: string;
378
378
  triggerPrice?: number;
379
379
  }>): Promise<import("pocketbase").RecordModel[]>;
380
+ deleteAndBulCreateAllOrders(payload: {
381
+ account: ExchangeType & {
382
+ id: string;
383
+ };
384
+ symbol: string;
385
+ all_orders: Array<{
386
+ symbol: string;
387
+ price: number;
388
+ quantity: number;
389
+ kind: "long" | "short";
390
+ side: "buy" | "sell";
391
+ stop: number;
392
+ order_id: string;
393
+ triggerPrice?: number;
394
+ }>;
395
+ }): Promise<void>;
380
396
  cancelLimitOrders(payload: {
381
397
  symbol: string;
382
398
  kind: "long" | "short";
@@ -730,11 +746,140 @@ export declare function determine_break_even_price(payload: {
730
746
  price: number;
731
747
  direction: string;
732
748
  };
749
+ declare class ExchangePosition {
750
+ exchange: BaseExchange;
751
+ exchange_account: ExchangeAccount$1;
752
+ private app_db;
753
+ private instance;
754
+ constructor(payload: {
755
+ exchange: BaseExchange;
756
+ app_db: AppDatabase;
757
+ instance: PositionsView;
758
+ exchange_account: ExchangeAccount$1;
759
+ without_view?: PositionsView;
760
+ });
761
+ get symbol(): any;
762
+ get kind(): any;
763
+ get account(): any;
764
+ cancelOrders(payload: {
765
+ limit?: boolean;
766
+ price?: number;
767
+ }): Promise<void | {
768
+ success: boolean;
769
+ message: string;
770
+ exchange_result?: undefined;
771
+ error?: undefined;
772
+ } | {
773
+ success: boolean;
774
+ exchange_result: any;
775
+ message?: undefined;
776
+ error?: undefined;
777
+ } | {
778
+ success: boolean;
779
+ error: any;
780
+ message?: undefined;
781
+ exchange_result?: undefined;
782
+ }>;
783
+ getConfig(payload?: {
784
+ params?: {
785
+ entry?: number;
786
+ stop?: number;
787
+ risk_reward?: number;
788
+ risk?: number;
789
+ profit_percent?: number;
790
+ place_tp?: boolean;
791
+ profit?: number;
792
+ };
793
+ }): Promise<ScheduledTrade | import("pocketbase").RecordModel>;
794
+ updateTargetPnl(): Promise<number>;
795
+ updateConfigPnl(): Promise<void>;
796
+ triggerTradeFromConfig(payload: {
797
+ place?: boolean;
798
+ raw?: boolean;
799
+ tp?: boolean;
800
+ stop?: boolean;
801
+ use_current?: boolean;
802
+ ignore_config?: boolean;
803
+ }): Promise<any>;
804
+ placeSharedOrder(action: "place_limit_orders" | "place_stop_orders" | "place_tp_orders", payload: {
805
+ entry: number;
806
+ stop: number;
807
+ risk_reward: number;
808
+ risk: number;
809
+ place?: boolean;
810
+ update_db?: boolean;
811
+ raw?: boolean;
812
+ use_current?: boolean;
813
+ }): Promise<any>;
814
+ buildAppConfig(payload: {
815
+ entry: number;
816
+ stop: number;
817
+ risk_reward: number;
818
+ risk: number;
819
+ profit?: number;
820
+ update_db?: boolean;
821
+ profit_percent?: number;
822
+ }): Promise<AppConfig>;
823
+ placeConfigOrders(app_config: AppConfig, solution: {
824
+ risk_reward: number;
825
+ entry: number;
826
+ stop: number;
827
+ risk_per_trade: number;
828
+ avg_size: number;
829
+ neg_pnl: number;
830
+ min_size: number;
831
+ symbol: string;
832
+ }, place?: boolean, skip_stop?: boolean): Promise<{
833
+ entry_orders: {
834
+ orders: {
835
+ entry: any;
836
+ quantity: any;
837
+ reverse_avg_entry: any;
838
+ reverse_avg_quantity: any;
839
+ avg_entry: any;
840
+ avg_size: any;
841
+ }[];
842
+ kind: "long" | "short";
843
+ };
844
+ stop_orders: {
845
+ stop: number;
846
+ final_stop: number;
847
+ kind: "long" | "short";
848
+ quantity: any;
849
+ is_limit: boolean;
850
+ neg_pnl: any;
851
+ };
852
+ trades: any[];
853
+ }>;
854
+ determineAmountToBuy(payload: {
855
+ orders: any[];
856
+ kind: "long" | "short";
857
+ refresh?: boolean;
858
+ decimal_places?: string;
859
+ price_places?: string;
860
+ cancel?: boolean;
861
+ place?: boolean;
862
+ }): Promise<any[]>;
863
+ refresh(live_refresh?: boolean): Promise<{
864
+ instance: PositionsView;
865
+ existingOrders: void | import("pocketbase").RecordModel[];
866
+ }>;
867
+ placeTrade(payload: {
868
+ place?: boolean;
869
+ tp?: boolean;
870
+ stop?: boolean;
871
+ raw?: boolean;
872
+ cancel?: boolean;
873
+ ignore_config?: boolean;
874
+ }): Promise<any>;
875
+ }
733
876
  declare class ExchangeAccount$1 {
734
877
  private instance;
735
878
  exchange: BaseExchange;
736
879
  main_exchange?: BaseExchange;
737
880
  private app_db;
881
+ private long_position?;
882
+ private short_position?;
738
883
  constructor(payload: ExchangeType, options: {
739
884
  exchange: BaseExchange;
740
885
  app_db: AppDatabase;
@@ -751,6 +896,11 @@ declare class ExchangeAccount$1 {
751
896
  refresh?: boolean;
752
897
  refresh_symbol_config?: boolean;
753
898
  }): Promise<import("pocketbase").RecordModel>;
899
+ initializePositions(payload: {
900
+ symbol: string;
901
+ as_view?: boolean;
902
+ kind: "long" | "short";
903
+ }): Promise<ExchangePosition>;
754
904
  getActiveAccount(payload: {
755
905
  symbol: string;
756
906
  full?: boolean;
@@ -764,6 +914,16 @@ declare class ExchangeAccount$1 {
764
914
  current_price: any;
765
915
  exchange: any;
766
916
  }>;
917
+ refreshAccount(payload: {
918
+ symbol: string;
919
+ live_refresh?: boolean;
920
+ leverage?: number;
921
+ }): Promise<(PositionsView & {
922
+ expand?: {
923
+ config: ScheduledTrade;
924
+ account: ExchangeAccount;
925
+ };
926
+ })[]>;
767
927
  syncAccount(options: {
768
928
  symbol: string;
769
929
  kind?: "long" | "short";
@@ -780,9 +940,9 @@ declare class ExchangeAccount$1 {
780
940
  getRunningInstanceFromDB(symbol: string): Promise<TradeBlockTracking>;
781
941
  syncOrders(options: {
782
942
  symbol: string;
783
- kind: "long" | "short";
943
+ kind?: "long" | "short";
784
944
  update?: boolean;
785
- }): Promise<import("pocketbase").RecordModel[]>;
945
+ }): Promise<void | import("pocketbase").RecordModel[]>;
786
946
  toggleStopBuying(payload: {
787
947
  symbol: string;
788
948
  kind: "long" | "short";
@@ -1032,7 +1192,7 @@ declare class ExchangeAccount$1 {
1032
1192
  symbol: string;
1033
1193
  kind: "long" | "short";
1034
1194
  revert?: boolean;
1035
- }): Promise<import("pocketbase").RecordModel[]>;
1195
+ }): Promise<void | import("pocketbase").RecordModel[]>;
1036
1196
  windDownSymbol(payload: {
1037
1197
  symbol: string;
1038
1198
  risk_reward?: number;
@@ -1079,7 +1239,6 @@ declare class ExchangeAccount$1 {
1079
1239
  symbol: string;
1080
1240
  kind: "long" | "short";
1081
1241
  type: "limit" | "stop" | "tp";
1082
- refresh?: boolean;
1083
1242
  }): Promise<import("pocketbase").RecordModel[]>;
1084
1243
  syncPositionConfigs(payload: {
1085
1244
  symbol: string;
package/dist/index.js CHANGED
@@ -32376,10 +32376,6 @@ class AppDatabase {
32376
32376
  }
32377
32377
  async deleteAndRecreateOrders(account, options, all_orders = []) {
32378
32378
  const { symbol, kind } = options;
32379
- await this.getOrders(account, {
32380
- symbol,
32381
- kind
32382
- });
32383
32379
  const exchange_db_instance = await this.get_exchange_db_instance(account);
32384
32380
  console.log(`Fetching existing DB orders for ${account.owner}/${account.exchange} - ${symbol} (${options.kind}) to delete...`);
32385
32381
  let pocketbase_ids_to_delete = [];
@@ -32436,6 +32432,59 @@ class AppDatabase {
32436
32432
  kind
32437
32433
  });
32438
32434
  }
32435
+ async deleteAndBulCreateAllOrders(payload) {
32436
+ const { account, symbol, all_orders } = payload;
32437
+ console.log(`Fetching existing DB orders for ${account.owner}/${account.exchange} - ${symbol} to delete...`);
32438
+ let pocketbase_ids_to_delete = [];
32439
+ try {
32440
+ const db_orders_to_delete = await this.pb.collection("orders").getFullList({
32441
+ filter: `symbol:lower="${symbol.toLowerCase()}" && account.owner:lower="${account.owner.toLowerCase()}" && account.exchange:lower="${account.exchange.toLowerCase()}"`
32442
+ });
32443
+ pocketbase_ids_to_delete = db_orders_to_delete.map((o) => o.id);
32444
+ console.log(`Found ${pocketbase_ids_to_delete.length} existing DB orders to delete.`);
32445
+ } catch (error) {
32446
+ console.error("Error fetching DB orders for deletion:", error);
32447
+ }
32448
+ if (pocketbase_ids_to_delete.length > 0) {
32449
+ console.log(`Deleting ${pocketbase_ids_to_delete.length} existing orders from PocketBase...`);
32450
+ for (let i2 = 0;i2 < pocketbase_ids_to_delete.length; i2 += 5) {
32451
+ const batch_to_delete = pocketbase_ids_to_delete.slice(i2, i2 + 5);
32452
+ try {
32453
+ await Promise.all(batch_to_delete.map((id) => this.pb.collection("orders").delete(id)));
32454
+ } catch (error) {
32455
+ console.error(`Error deleting batch starting at index ${i2}:`, error, "Batch IDs:", batch_to_delete);
32456
+ }
32457
+ }
32458
+ console.log("Finished deleting existing DB orders.");
32459
+ }
32460
+ console.log(`Found ${all_orders.length} current orders on the exchange.`);
32461
+ if (all_orders.length > 0) {
32462
+ console.log(`Recreating ${all_orders.length} orders in PocketBase...`);
32463
+ for (let i2 = 0;i2 < all_orders.length; i2 += 45) {
32464
+ const orderChunk = all_orders.slice(i2, i2 + 45);
32465
+ const batch = this.pb.createBatch();
32466
+ for (const order of orderChunk) {
32467
+ const order_data = {
32468
+ symbol,
32469
+ price: order.price,
32470
+ quantity: order.quantity,
32471
+ kind: order.kind,
32472
+ side: order.side,
32473
+ stop: order.stop || order.triggerPrice || 0,
32474
+ order_id: order.order_id.toString(),
32475
+ account: account.id
32476
+ };
32477
+ batch.collection("orders").create(order_data);
32478
+ }
32479
+ try {
32480
+ await batch.send();
32481
+ } catch (error) {
32482
+ console.error(`Error creating batch starting at index ${i2}:`, error);
32483
+ }
32484
+ }
32485
+ console.log("Finished recreating orders in PocketBase.");
32486
+ }
32487
+ }
32439
32488
  async cancelLimitOrders(payload) {
32440
32489
  const { symbol, kind, account, cancelExchangeOrders } = payload;
32441
32490
  const side = kind === "long" ? "buy" : "sell";
@@ -36252,12 +36301,382 @@ function determine_break_even_price(payload) {
36252
36301
  };
36253
36302
  }
36254
36303
 
36304
+ // src/position.ts
36305
+ class ExchangePosition {
36306
+ exchange;
36307
+ exchange_account;
36308
+ app_db;
36309
+ instance;
36310
+ constructor(payload) {
36311
+ this.exchange = payload.exchange;
36312
+ this.app_db = payload.app_db;
36313
+ this.instance = payload.instance;
36314
+ this.exchange_account = payload.exchange_account;
36315
+ }
36316
+ get symbol() {
36317
+ return this.instance.symbol;
36318
+ }
36319
+ get kind() {
36320
+ return this.instance.kind;
36321
+ }
36322
+ get account() {
36323
+ return this.instance.account;
36324
+ }
36325
+ async cancelOrders(payload) {
36326
+ const { limit, price: _price } = payload;
36327
+ if (limit) {
36328
+ return await this.app_db.cancelLimitOrders({
36329
+ symbol: this.symbol,
36330
+ kind: this.kind,
36331
+ account: this.account,
36332
+ cancelExchangeOrders: (p) => this.exchange.cancelOrders(p)
36333
+ });
36334
+ }
36335
+ let price = _price || 0;
36336
+ if (!price) {
36337
+ price = this.instance?.take_profit || 0;
36338
+ }
36339
+ let result = await this.app_db.cancelOrders({
36340
+ cancelExchangeOrders: (p) => this.exchange.cancelOrders(p),
36341
+ kind: this.kind,
36342
+ account: this.account,
36343
+ symbol: this.symbol,
36344
+ price
36345
+ });
36346
+ return result;
36347
+ }
36348
+ async getConfig(payload) {
36349
+ if (payload?.params) {
36350
+ const db_position = this.instance;
36351
+ if (db_position) {
36352
+ const config = db_position.expand?.config;
36353
+ const params = {
36354
+ entry: payload.params.entry !== undefined ? payload.params.entry : config?.entry,
36355
+ stop: payload.params.stop !== undefined ? payload.params.stop : config?.stop,
36356
+ risk_reward: payload.params.risk_reward !== undefined ? payload.params.risk_reward : config?.risk_reward,
36357
+ risk: payload.params.risk !== undefined ? payload.params.risk : config?.risk,
36358
+ profit_percent: payload.params.profit_percent !== undefined ? payload.params.profit_percent : config?.profit_percent,
36359
+ place_tp: payload.params.place_tp !== undefined ? payload.params.place_tp : true,
36360
+ profit: payload.params.profit !== undefined ? payload.params.profit : config?.profit
36361
+ };
36362
+ return await this.app_db.createOrUpdatePositionConfig(this.instance, params);
36363
+ }
36364
+ }
36365
+ return await this.app_db.getPositionConfig({
36366
+ symbol: this.symbol,
36367
+ kind: this.kind,
36368
+ account: this.account
36369
+ });
36370
+ }
36371
+ async updateTargetPnl() {
36372
+ const position2 = this.instance;
36373
+ if (position2?.expand?.config) {
36374
+ const config = position2.expand.config;
36375
+ let _profit = config.profit;
36376
+ let _profit_percent = config?.profit_percent;
36377
+ if (_profit_percent && (position2?.quantity || 0) > 0) {
36378
+ _profit = to_f(position2.quantity * _profit_percent * position2.entry / 100);
36379
+ }
36380
+ await this.app_db.update_db_position(position2, {
36381
+ target_pnl: _profit
36382
+ });
36383
+ return _profit;
36384
+ }
36385
+ return 0;
36386
+ }
36387
+ async updateConfigPnl() {
36388
+ const position2 = this.instance;
36389
+ if (!position2?.config) {
36390
+ const config = await this.getConfig();
36391
+ if (config) {
36392
+ await this.app_db.update_db_position(position2, { config: config.id });
36393
+ await this.updateTargetPnl();
36394
+ await this.app_db.update_db_position(position2, { config: null });
36395
+ }
36396
+ } else {
36397
+ await this.updateTargetPnl();
36398
+ }
36399
+ }
36400
+ async triggerTradeFromConfig(payload) {
36401
+ const { place = true, stop, use_current, ignore_config } = payload;
36402
+ const position2 = this.instance;
36403
+ const config = await this.getConfig();
36404
+ let condition = ignore_config ? true : position2?.config;
36405
+ if (condition) {
36406
+ let entry = payload.tp ? position2.entry || config.entry : config.entry;
36407
+ const v = stop ? "place_stop_orders" : "place_limit_orders";
36408
+ return await this.placeSharedOrder(v, {
36409
+ entry,
36410
+ stop: config.stop,
36411
+ risk_reward: config.risk_reward,
36412
+ risk: config.risk,
36413
+ place,
36414
+ raw: payload.raw,
36415
+ use_current
36416
+ });
36417
+ }
36418
+ }
36419
+ async placeSharedOrder(action, payload) {
36420
+ const app_config = await this.buildAppConfig({
36421
+ entry: payload.entry,
36422
+ stop: payload.stop,
36423
+ risk_reward: payload.risk_reward,
36424
+ risk: payload.risk,
36425
+ profit: 0,
36426
+ update_db: payload.update_db
36427
+ });
36428
+ const { entry_orders, stop_orders, trades } = await this.placeConfigOrders(app_config, {
36429
+ risk_reward: payload.risk_reward,
36430
+ entry: payload.entry,
36431
+ stop: payload.stop,
36432
+ risk_per_trade: payload.risk,
36433
+ avg_size: 0,
36434
+ neg_pnl: 0,
36435
+ min_size: app_config.min_size,
36436
+ symbol: this.symbol
36437
+ }, false);
36438
+ if (payload.raw) {
36439
+ let actual_orders_to_buy = await this.determineAmountToBuy({
36440
+ orders: trades,
36441
+ kind: app_config.kind,
36442
+ decimal_places: app_config.decimal_places,
36443
+ price_places: app_config.price_places,
36444
+ place: payload.place
36445
+ });
36446
+ if (action === "place_limit_orders" && payload.place) {
36447
+ return await this.exchange.createLimitPurchaseOrders({
36448
+ orders: actual_orders_to_buy.map((x) => ({
36449
+ entry: x.entry,
36450
+ quantity: x.quantity
36451
+ })),
36452
+ kind: app_config.kind,
36453
+ decimal_places: app_config.decimal_places,
36454
+ price_places: app_config.price_places,
36455
+ symbol: this.symbol
36456
+ });
36457
+ }
36458
+ return actual_orders_to_buy;
36459
+ }
36460
+ if (action === "place_limit_orders" && payload.place) {
36461
+ let result = await this.exchange.bulkPlaceLimitOrders({
36462
+ orders: trades.map((x) => ({
36463
+ entry: x.entry,
36464
+ quantity: x.quantity
36465
+ })),
36466
+ kind: app_config.kind,
36467
+ price_places: app_config.price_places,
36468
+ decimal_places: app_config.decimal_places,
36469
+ symbol: this.symbol,
36470
+ place: payload.place
36471
+ });
36472
+ await this.exchange_account.getLiveExchangeInstance({
36473
+ symbol: this.symbol,
36474
+ refresh: true
36475
+ });
36476
+ return result;
36477
+ }
36478
+ if (action === "place_stop_orders" && payload.place) {
36479
+ const instance = this.instance;
36480
+ let result = await this.exchange.placeStopOrders({
36481
+ symbol: this.symbol,
36482
+ quantity: payload.use_current ? instance.quantity : trades[0].avg_size,
36483
+ kind: app_config.kind,
36484
+ stop: payload.stop,
36485
+ price_places: app_config.price_places,
36486
+ decimal_places: app_config.decimal_places,
36487
+ place: true
36488
+ });
36489
+ await this.exchange_account.getLiveExchangeInstance({
36490
+ symbol: this.symbol,
36491
+ refresh: true
36492
+ });
36493
+ return result;
36494
+ }
36495
+ return {
36496
+ entry_orders,
36497
+ stop_orders
36498
+ };
36499
+ }
36500
+ async buildAppConfig(payload) {
36501
+ let config = await this.app_db.getSymbolConfigFromDB(this.symbol);
36502
+ const app_config = buildAppConfig(config, {
36503
+ ...payload,
36504
+ symbol: this.symbol
36505
+ });
36506
+ if (payload.update_db) {
36507
+ const db_position = this.instance;
36508
+ if (db_position) {
36509
+ await this.app_db.createOrUpdatePositionConfig(db_position, {
36510
+ entry: payload.entry,
36511
+ stop: payload.stop,
36512
+ risk_reward: payload.risk_reward,
36513
+ risk: payload.risk,
36514
+ profit_percent: payload.profit_percent
36515
+ });
36516
+ }
36517
+ }
36518
+ return app_config;
36519
+ }
36520
+ async placeConfigOrders(app_config, solution, place, skip_stop) {
36521
+ app_config.entry = solution.entry;
36522
+ app_config.stop = solution.stop;
36523
+ app_config.risk_per_trade = solution.risk_per_trade;
36524
+ app_config.min_size = solution.min_size;
36525
+ app_config.risk_reward = solution.risk_reward;
36526
+ const options = {
36527
+ take_profit: null,
36528
+ entry: app_config.entry,
36529
+ stop: app_config.stop,
36530
+ raw_instance: null,
36531
+ risk: app_config.risk_per_trade,
36532
+ no_of_trades: undefined,
36533
+ risk_reward: app_config.risk_reward,
36534
+ kind: app_config.kind,
36535
+ increase: true,
36536
+ gap: app_config.gap,
36537
+ rr: app_config.rr,
36538
+ price_places: app_config.price_places,
36539
+ decimal_places: app_config.decimal_places
36540
+ };
36541
+ const trades = sortedBuildConfig(app_config, options);
36542
+ const entry_orders = {
36543
+ orders: trades.map((x) => ({
36544
+ entry: x.entry,
36545
+ quantity: x.quantity,
36546
+ reverse_avg_entry: x.reverse_avg_entry,
36547
+ reverse_avg_quantity: x.reverse_avg_quantity,
36548
+ avg_entry: x.avg_entry,
36549
+ avg_size: x.avg_size
36550
+ })),
36551
+ kind: app_config.kind
36552
+ };
36553
+ const stop_orders = {
36554
+ stop: solution.stop,
36555
+ final_stop: solution.stop,
36556
+ kind: app_config.kind,
36557
+ quantity: trades[0]?.avg_size,
36558
+ is_limit: true,
36559
+ neg_pnl: trades[0]?.neg_pnl
36560
+ };
36561
+ if (place) {
36562
+ let arr = [
36563
+ this.exchange.bulkPlaceLimitOrders({
36564
+ orders: trades.map((x) => ({
36565
+ entry: x.entry,
36566
+ quantity: x.quantity
36567
+ })),
36568
+ kind: app_config.kind,
36569
+ decimal_places: app_config.decimal_places,
36570
+ price_places: app_config.price_places,
36571
+ symbol: solution.symbol,
36572
+ place
36573
+ })
36574
+ ];
36575
+ if (!skip_stop) {
36576
+ arr.push(this.exchange.placeStopOrders({
36577
+ symbol: solution.symbol,
36578
+ quantity: trades[0].avg_size,
36579
+ kind: app_config.kind,
36580
+ stop: solution.stop,
36581
+ price_places: app_config.price_places,
36582
+ decimal_places: app_config.decimal_places,
36583
+ place
36584
+ }));
36585
+ }
36586
+ await Promise.all(arr);
36587
+ }
36588
+ return {
36589
+ entry_orders,
36590
+ stop_orders,
36591
+ trades
36592
+ };
36593
+ }
36594
+ async determineAmountToBuy(payload) {
36595
+ const { orders, kind, decimal_places = "%.3f", refresh, cancel } = payload;
36596
+ const totalQuantity = orders.reduce((sum, order) => sum + (order.quantity || 0), 0);
36597
+ let runningTotal = to_f(totalQuantity, decimal_places);
36598
+ let sortedOrders = [...orders].sort((a, b) => (a.entry || 0) - (b.entry || 0));
36599
+ if (kind === "short") {
36600
+ sortedOrders.reverse();
36601
+ }
36602
+ const withCumulative = [];
36603
+ for (const order of sortedOrders) {
36604
+ withCumulative.push({
36605
+ ...order,
36606
+ cumulative_quantity: runningTotal
36607
+ });
36608
+ runningTotal -= order.quantity;
36609
+ runningTotal = to_f(runningTotal, decimal_places);
36610
+ }
36611
+ const { instance: position2, existingOrders } = await this.refresh(refresh);
36612
+ let filteredOrders = withCumulative.filter((order) => (order.cumulative_quantity || 0) > position2?.quantity).map((order) => ({
36613
+ ...order,
36614
+ price: order.entry,
36615
+ kind,
36616
+ side: kind.toLowerCase() === "long" ? "buy" : "sell"
36617
+ }));
36618
+ filteredOrders = filteredOrders.filter((k) => !existingOrders.map((j) => j.price).includes(k.price));
36619
+ const side = kind.toLowerCase() === "long" ? "buy" : "sell";
36620
+ const shouldCancel = existingOrders.filter((k) => !orders.map((j) => j.entry).includes(k.price) && k.side === side).map((u) => u.price);
36621
+ if (shouldCancel.length > 0 && cancel) {
36622
+ const pp = kind === "long" ? Math.max(...shouldCancel) : Math.min(...shouldCancel);
36623
+ const cancel_orders = await this.cancelOrders({
36624
+ price: pp
36625
+ });
36626
+ console.log("cancel_orders", cancel_orders);
36627
+ }
36628
+ return filteredOrders;
36629
+ }
36630
+ async refresh(live_refresh) {
36631
+ await this.exchange_account.refreshAccount({
36632
+ symbol: this.symbol,
36633
+ live_refresh
36634
+ });
36635
+ const instance = await this.exchange_account.syncAccount({
36636
+ symbol: this.symbol,
36637
+ kind: this.kind,
36638
+ update: true
36639
+ });
36640
+ let existingOrders = await this.exchange_account.syncOrders({
36641
+ symbol: this.symbol,
36642
+ kind: this.kind
36643
+ });
36644
+ return { instance, existingOrders };
36645
+ }
36646
+ async placeTrade(payload) {
36647
+ const { place, tp, raw: _raw, cancel, stop, ignore_config } = payload;
36648
+ if (cancel) {
36649
+ await this.cancelOrders({
36650
+ limit: true
36651
+ });
36652
+ }
36653
+ if (place) {
36654
+ return await this.triggerTradeFromConfig({
36655
+ raw: payload.raw,
36656
+ stop,
36657
+ ignore_config
36658
+ });
36659
+ }
36660
+ const rr = await this.refresh(true);
36661
+ await this.updateTargetPnl();
36662
+ if (tp) {
36663
+ await this.exchange_account.placeProfitAndStop({
36664
+ symbol: this.symbol,
36665
+ trigger: true
36666
+ });
36667
+ }
36668
+ return rr.existingOrders;
36669
+ }
36670
+ }
36671
+
36255
36672
  // src/exchange-account.ts
36256
36673
  class ExchangeAccount {
36257
36674
  instance;
36258
36675
  exchange;
36259
36676
  main_exchange;
36260
36677
  app_db;
36678
+ long_position;
36679
+ short_position;
36261
36680
  constructor(payload, options) {
36262
36681
  this.instance = payload;
36263
36682
  this.exchange = options.exchange;
@@ -36297,6 +36716,32 @@ class ExchangeAccount {
36297
36716
  }
36298
36717
  return result;
36299
36718
  }
36719
+ async initializePositions(payload) {
36720
+ const positions = await this.syncAccount({
36721
+ symbol: payload.symbol,
36722
+ as_view: payload.as_view
36723
+ });
36724
+ const raw_positions = await this.syncAccount({
36725
+ symbol: payload.symbol
36726
+ });
36727
+ const long_position = positions.find((x) => x.kind === "long");
36728
+ const short_position = positions.find((x) => x.kind === "short");
36729
+ this.long_position = new ExchangePosition({
36730
+ exchange: this.exchange,
36731
+ exchange_account: this,
36732
+ instance: long_position,
36733
+ app_db: this.app_db,
36734
+ without_view: raw_positions.find((x) => x.kind === "long")
36735
+ });
36736
+ this.short_position = new ExchangePosition({
36737
+ exchange: this.exchange,
36738
+ exchange_account: this,
36739
+ instance: short_position,
36740
+ app_db: this.app_db,
36741
+ without_view: raw_positions.find((x) => x.kind === "short")
36742
+ });
36743
+ return payload.kind === "long" ? this.long_position : this.short_position;
36744
+ }
36300
36745
  async getActiveAccount(payload) {
36301
36746
  const { symbol, full = false, refresh = false } = payload;
36302
36747
  const symbol_config = await this.recomputeSymbolConfig({
@@ -36316,6 +36761,27 @@ class ExchangeAccount {
36316
36761
  }
36317
36762
  return _all.active_account;
36318
36763
  }
36764
+ async refreshAccount(payload) {
36765
+ const { symbol, live_refresh, leverage } = payload;
36766
+ const active_account = await this.getActiveAccount({
36767
+ refresh: live_refresh,
36768
+ symbol
36769
+ });
36770
+ if (leverage) {
36771
+ await this.exchange.setLeverage({ symbol, leverage });
36772
+ }
36773
+ const db_positions = await this.app_db.createOrUpdatePositions(this.instance, {
36774
+ symbol,
36775
+ long_position: active_account.position.long,
36776
+ short_position: active_account.position.short,
36777
+ usd_balance: active_account.usd_balance || 0
36778
+ });
36779
+ await this.syncOrders({
36780
+ symbol,
36781
+ update: true
36782
+ });
36783
+ return db_positions;
36784
+ }
36319
36785
  async syncAccount(options) {
36320
36786
  const { symbol, update = false, live_refresh = false } = options;
36321
36787
  if (!update) {
@@ -36330,18 +36796,10 @@ class ExchangeAccount {
36330
36796
  }
36331
36797
  return db_positions2;
36332
36798
  }
36333
- const active_account = await this.getActiveAccount({
36334
- refresh: live_refresh,
36335
- symbol
36336
- });
36337
- if (options.leverage) {
36338
- await this.exchange.setLeverage({ symbol, leverage: options.leverage });
36339
- }
36340
- const db_positions = await this.app_db.createOrUpdatePositions(this.instance, {
36799
+ const db_positions = await this.refreshAccount({
36341
36800
  symbol,
36342
- long_position: active_account.position.long,
36343
- short_position: active_account.position.short,
36344
- usd_balance: active_account.usd_balance || 0
36801
+ live_refresh,
36802
+ leverage: options.leverage
36345
36803
  });
36346
36804
  if (options.kind) {
36347
36805
  return db_positions.find((x) => x.kind === options.kind);
@@ -36353,7 +36811,7 @@ class ExchangeAccount {
36353
36811
  }
36354
36812
  async syncOrders(options) {
36355
36813
  const { symbol, update = false, kind } = options;
36356
- if (!update) {
36814
+ if (!update && kind) {
36357
36815
  const db_orders = await this.app_db.getOrders(this.instance, {
36358
36816
  symbol: options.symbol,
36359
36817
  kind: options.kind
@@ -36363,14 +36821,16 @@ class ExchangeAccount {
36363
36821
  const active_account = await this.getActiveAccount({
36364
36822
  symbol
36365
36823
  });
36366
- const orders = kind === "long" ? active_account.orders.long.entries : active_account.orders.short.entries;
36367
- const stop_orders = kind === "long" ? active_account.orders.long.stop_orders : active_account.orders.short.stop_orders;
36368
- const tp_orders = kind === "long" ? active_account.orders.long.tp_orders : active_account.orders.short.tp_orders;
36824
+ const orders = active_account.orders.long.entries.concat(active_account.orders.short.entries);
36825
+ const stop_orders = active_account.orders.long.stop_orders.concat(active_account.orders.short.stop_orders);
36826
+ const tp_orders = active_account.orders.long.tp_orders.concat(active_account.orders.short.tp_orders);
36369
36827
  const all_orders = [...orders, ...stop_orders, ...tp_orders];
36370
- return this.app_db.deleteAndRecreateOrders(this.instance, {
36828
+ const exchange_db_instance = await this.app_db.get_exchange_db_instance(this.instance);
36829
+ return this.app_db.deleteAndBulCreateAllOrders({
36830
+ account: exchange_db_instance,
36371
36831
  symbol,
36372
- kind
36373
- }, all_orders);
36832
+ all_orders
36833
+ });
36374
36834
  }
36375
36835
  async toggleStopBuying(payload) {
36376
36836
  const { symbol, kind, should_stop = false } = payload;
@@ -36398,11 +36858,7 @@ class ExchangeAccount {
36398
36858
  async cancelOrders(payload) {
36399
36859
  const { symbol, kind, price: _price, all, stop, limit } = payload;
36400
36860
  let price = _price || 0;
36401
- await this.getLiveExchangeInstance({
36402
- symbol,
36403
- refresh: true
36404
- });
36405
- await this.syncOrders({
36861
+ await this.syncAccount({
36406
36862
  symbol,
36407
36863
  kind,
36408
36864
  update: true
@@ -36630,8 +37086,7 @@ class ExchangeAccount {
36630
37086
  });
36631
37087
  let existingOrders = await this.syncOrders({
36632
37088
  symbol,
36633
- kind,
36634
- update: true
37089
+ kind
36635
37090
  });
36636
37091
  let filteredOrders = withCumulative.filter((order) => (order.cumulative_quantity || 0) > position2?.quantity).map((order) => ({
36637
37092
  ...order,
@@ -36947,16 +37402,6 @@ class ExchangeAccount {
36947
37402
  symbol,
36948
37403
  update: true
36949
37404
  });
36950
- await this.syncOrders({
36951
- symbol,
36952
- kind: "long",
36953
- update: true
36954
- });
36955
- await this.syncOrders({
36956
- symbol,
36957
- kind: "short",
36958
- update: true
36959
- });
36960
37405
  const long_position = db_positions.find((x) => x.kind === "long");
36961
37406
  const short_position = db_positions.find((x) => x.kind === "short");
36962
37407
  if (long_position && long_position.quantity === 0) {
@@ -37033,11 +37478,6 @@ class ExchangeAccount {
37033
37478
  }
37034
37479
  async build_short_order(payload) {
37035
37480
  const { symbol, kind } = payload;
37036
- await this.syncOrders({
37037
- symbol,
37038
- kind,
37039
- update: true
37040
- });
37041
37481
  const position2 = await this.syncAccount({
37042
37482
  symbol,
37043
37483
  kind,
@@ -37118,6 +37558,11 @@ class ExchangeAccount {
37118
37558
  price_places: symbol_config.price_places,
37119
37559
  decimal_places: symbol_config.decimal_places
37120
37560
  });
37561
+ await this.syncAccount({
37562
+ symbol,
37563
+ update: true,
37564
+ live_refresh: true
37565
+ });
37121
37566
  }
37122
37567
  async placeSingleOrder(payload) {
37123
37568
  const { symbol, kind } = payload;
@@ -37177,11 +37622,6 @@ class ExchangeAccount {
37177
37622
  }
37178
37623
  async verifyStopLoss(payload) {
37179
37624
  const { symbol, kind, revert } = payload;
37180
- await this.syncOrders({
37181
- symbol,
37182
- kind,
37183
- update: true
37184
- });
37185
37625
  let original = null;
37186
37626
  if (revert) {
37187
37627
  original = await this.getOriginalPlannedStop({
@@ -37203,17 +37643,11 @@ class ExchangeAccount {
37203
37643
  });
37204
37644
  return await this.syncOrders({
37205
37645
  symbol,
37206
- kind,
37207
- update: true
37646
+ kind
37208
37647
  });
37209
37648
  }
37210
37649
  if (true) {
37211
37650
  const opposite_kind = kind === "long" ? "short" : "long";
37212
- await this.syncOrders({
37213
- symbol,
37214
- kind: opposite_kind,
37215
- update: true
37216
- });
37217
37651
  await this.cancelOrders({
37218
37652
  symbol,
37219
37653
  kind: opposite_kind,
@@ -37224,11 +37658,6 @@ class ExchangeAccount {
37224
37658
  kind: opposite_kind,
37225
37659
  trigger: true
37226
37660
  });
37227
- await this.syncOrders({
37228
- symbol,
37229
- kind,
37230
- update: true
37231
- });
37232
37661
  }
37233
37662
  }
37234
37663
  async windDownSymbol(payload) {
@@ -37506,8 +37935,7 @@ class ExchangeAccount {
37506
37935
  const orders = await this.getOrders({
37507
37936
  symbol,
37508
37937
  kind: "short",
37509
- type: "limit",
37510
- refresh: true
37938
+ type: "limit"
37511
37939
  });
37512
37940
  if (orders.length > 0) {
37513
37941
  await this.toggleStopBuying({
@@ -37558,16 +37986,6 @@ class ExchangeAccount {
37558
37986
  symbol,
37559
37987
  update: true
37560
37988
  });
37561
- await this.syncOrders({
37562
- symbol,
37563
- kind: "long",
37564
- update: true
37565
- });
37566
- await this.syncOrders({
37567
- symbol,
37568
- kind: "short",
37569
- update: true
37570
- });
37571
37989
  }
37572
37990
  }
37573
37991
  async updateAllPositionsWithNoConfig(payload) {
@@ -37683,13 +38101,7 @@ class ExchangeAccount {
37683
38101
  }
37684
38102
  }
37685
38103
  async getOrders(payload) {
37686
- const { symbol, kind, type, refresh = false } = payload;
37687
- if (refresh) {
37688
- await this.syncOrders({
37689
- symbol,
37690
- kind
37691
- });
37692
- }
38104
+ const { symbol, kind, type } = payload;
37693
38105
  let side;
37694
38106
  if (kind == "long") {
37695
38107
  if (type === "limit") {
@@ -37949,8 +38361,7 @@ class ExchangeAccount {
37949
38361
  });
37950
38362
  const result = await this.syncOrders({
37951
38363
  symbol,
37952
- kind,
37953
- update: true
38364
+ kind
37954
38365
  });
37955
38366
  await this.updateTargetPnl({
37956
38367
  symbol,
@@ -38078,13 +38489,6 @@ class App {
38078
38489
  kind: payload.kind,
38079
38490
  update: true
38080
38491
  });
38081
- if (payload.kind) {
38082
- await exchange_account.syncOrders({
38083
- symbol: payload.symbol,
38084
- kind: payload.kind,
38085
- update: true
38086
- });
38087
- }
38088
38492
  await this.app_db.updateRunningInstance(db_running_instance.id, false);
38089
38493
  return true;
38090
38494
  }
@@ -38269,6 +38673,7 @@ class App {
38269
38673
  symbol: position2.symbol,
38270
38674
  kind: position2.kind
38271
38675
  });
38676
+ await new Promise((resolve) => setTimeout(resolve, 5000));
38272
38677
  console.log("result", result);
38273
38678
  }
38274
38679
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-40",
4
+ "version": "0.0.2-43",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",