@gbozee/ultimate 0.0.2-33 → 0.0.2-36

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.
@@ -263,5 +263,19 @@ export declare function generate_config_params(app_config: AppConfig, payload: {
263
263
  neg_pnl: any;
264
264
  risk: number;
265
265
  };
266
+ export declare function determine_break_even_price(payload: {
267
+ long_position: {
268
+ entry: number;
269
+ quantity: number;
270
+ };
271
+ short_position: {
272
+ entry: number;
273
+ quantity: number;
274
+ };
275
+ fee_percent?: number;
276
+ }): {
277
+ price: number;
278
+ direction: string;
279
+ };
266
280
 
267
281
  export {};
@@ -1305,11 +1305,24 @@ function generate_config_params(app_config, payload) {
1305
1305
  risk: payload.risk
1306
1306
  };
1307
1307
  }
1308
+ function determine_break_even_price(payload) {
1309
+ const { long_position, short_position, fee_percent = 0.05 / 100 } = payload;
1310
+ const long_notional = long_position.entry * long_position.quantity;
1311
+ const short_notional = short_position.entry * short_position.quantity;
1312
+ const net_quantity = long_position.quantity - short_position.quantity;
1313
+ const net_capital = Math.abs(long_notional - short_notional);
1314
+ const break_even_price = net_capital / (Math.abs(net_quantity) + fee_percent * Math.abs(net_quantity));
1315
+ return {
1316
+ price: break_even_price,
1317
+ direction: net_quantity > 0 ? "long" : "short"
1318
+ };
1319
+ }
1308
1320
  export {
1309
1321
  sortedBuildConfig,
1310
1322
  get_app_config_and_max_size,
1311
1323
  getOptimumStopAndRisk,
1312
1324
  generate_config_params,
1325
+ determine_break_even_price,
1313
1326
  determine_average_entry_and_size,
1314
1327
  createArray,
1315
1328
  buildConfig,
package/dist/index.d.ts CHANGED
@@ -183,6 +183,13 @@ export interface BaseExchange {
183
183
  asset: string;
184
184
  amount: number;
185
185
  }): Promise<any>;
186
+ placeMarketOrder(payload: {
187
+ symbol: string;
188
+ kind: "long" | "short";
189
+ quantity: number;
190
+ price_places?: string;
191
+ decimal_places?: string;
192
+ }): Promise<any>;
186
193
  }
187
194
  export interface BaseSystemFields {
188
195
  id: string;
@@ -410,6 +417,11 @@ export declare class AppDatabase {
410
417
  }>;
411
418
  getMoverExchangeInstances(): Promise<ExchangeAccount[]>;
412
419
  updateScheduledTrade(id: string, payload: any): Promise<import("pocketbase").RecordModel>;
420
+ getPositionsToAutoFollow(): Promise<(Position$1 & {
421
+ expand: {
422
+ account: ExchangeAccount;
423
+ };
424
+ })[]>;
413
425
  createOrUpdatePositionConfig(db_position: any, payload: {
414
426
  entry: number;
415
427
  stop: number;
@@ -709,6 +721,20 @@ export declare function generate_config_params(app_config: AppConfig, payload: {
709
721
  neg_pnl: any;
710
722
  risk: number;
711
723
  };
724
+ export declare function determine_break_even_price(payload: {
725
+ long_position: {
726
+ entry: number;
727
+ quantity: number;
728
+ };
729
+ short_position: {
730
+ entry: number;
731
+ quantity: number;
732
+ };
733
+ fee_percent?: number;
734
+ }): {
735
+ price: number;
736
+ direction: string;
737
+ };
712
738
  declare class ExchangeAccount$1 {
713
739
  private instance;
714
740
  exchange: BaseExchange;
@@ -793,6 +819,12 @@ declare class ExchangeAccount$1 {
793
819
  symbol: string;
794
820
  orders: number[];
795
821
  }): Promise<any>;
822
+ getBreakEvenPrice(payload: {
823
+ symbol: string;
824
+ }): Promise<{
825
+ price: number;
826
+ direction: string;
827
+ }>;
796
828
  buildAppConfig(payload: {
797
829
  entry: number;
798
830
  stop: number;
@@ -803,6 +835,17 @@ declare class ExchangeAccount$1 {
803
835
  update_db?: boolean;
804
836
  profit_percent?: number;
805
837
  }): Promise<AppConfig>;
838
+ buildTrades(payload: {
839
+ symbol: string;
840
+ kind: "long" | "short";
841
+ risk?: number;
842
+ }): Promise<{
843
+ trades: any[];
844
+ max_size: any;
845
+ last_price: any;
846
+ total_size: number;
847
+ avg_entry: number;
848
+ }>;
806
849
  placeConfigOrders(app_config: AppConfig, solution: {
807
850
  risk_reward: number;
808
851
  entry: number;
@@ -837,9 +880,11 @@ declare class ExchangeAccount$1 {
837
880
  determineAmountToBuy(payload: {
838
881
  orders: any[];
839
882
  kind: "long" | "short";
883
+ refresh?: boolean;
840
884
  decimal_places?: string;
841
885
  price_places?: string;
842
886
  symbol: string;
887
+ cancel?: boolean;
843
888
  place?: boolean;
844
889
  }): Promise<any[]>;
845
890
  placeSharedOrder(action: "place_limit_orders" | "place_stop_orders" | "place_tp_orders", payload: {
@@ -853,6 +898,12 @@ declare class ExchangeAccount$1 {
853
898
  raw?: boolean;
854
899
  use_current?: boolean;
855
900
  }): Promise<any>;
901
+ getOrCreatePositionConfig(payload: {
902
+ symbol: string;
903
+ kind: "long" | "short";
904
+ risk?: number;
905
+ risk_reward?: number;
906
+ }): Promise<ScheduledTrade | import("pocketbase").RecordModel>;
856
907
  getPositionConfig(payload: {
857
908
  symbol: string;
858
909
  kind: "long" | "short";
@@ -962,6 +1013,15 @@ declare class ExchangeAccount$1 {
962
1013
  risk_reward?: number;
963
1014
  risk?: number;
964
1015
  }): Promise<any>;
1016
+ placeMarketOrder(payload: {
1017
+ symbol: string;
1018
+ kind: "long" | "short";
1019
+ quantity: number;
1020
+ }): Promise<void>;
1021
+ placeSingleOrder(payload: {
1022
+ symbol: string;
1023
+ kind: "long" | "short";
1024
+ }): Promise<string>;
965
1025
  triggerTradeFromConfig(payload: {
966
1026
  symbol: string;
967
1027
  kind: "long" | "short";
@@ -969,6 +1029,7 @@ declare class ExchangeAccount$1 {
969
1029
  raw?: boolean;
970
1030
  tp?: boolean;
971
1031
  stop?: boolean;
1032
+ use_current?: boolean;
972
1033
  }): Promise<any>;
973
1034
  verifyStopLoss(payload: {
974
1035
  symbol: string;
@@ -1148,6 +1209,7 @@ declare class App {
1148
1209
  refreshAllPositionsWithSymbol(payload: {
1149
1210
  symbol: string;
1150
1211
  }): Promise<void>;
1212
+ autoFollowPositions(): Promise<void>;
1151
1213
  getMoverExchangeInstances(): Promise<ExchangeAccount[]>;
1152
1214
  updateTpOnAllMarkets(): Promise<void>;
1153
1215
  triggerMoverTask(payload: {
package/dist/index.js CHANGED
@@ -32491,6 +32491,13 @@ class AppDatabase {
32491
32491
  async updateScheduledTrade(id, payload) {
32492
32492
  return await this.pb.collection("scheduled_trades").update(id, payload);
32493
32493
  }
32494
+ async getPositionsToAutoFollow() {
32495
+ const result = await this.pb.collection("positions").getFullList({
32496
+ filter: `follow=true`,
32497
+ expand: "account"
32498
+ });
32499
+ return result;
32500
+ }
32494
32501
  async createOrUpdatePositionConfig(db_position, payload) {
32495
32502
  let config = null;
32496
32503
  if (db_position.config) {
@@ -34835,6 +34842,19 @@ class BinanceExchange {
34835
34842
  return result;
34836
34843
  }
34837
34844
  }
34845
+ async placeMarketOrder(payload) {
34846
+ const { symbol, kind, quantity, price_places, decimal_places } = payload;
34847
+ const currentPrice = await this.get_current_price(symbol);
34848
+ return createLimitPurchaseOrders(this.client, symbol, price_places, decimal_places, [
34849
+ {
34850
+ force_market: true,
34851
+ side: kind === "long" ? "buy" : "sell",
34852
+ kind,
34853
+ quantity,
34854
+ price: currentPrice
34855
+ }
34856
+ ]);
34857
+ }
34838
34858
  }
34839
34859
  function getPricePlaces(target) {
34840
34860
  const numStr = target.toString();
@@ -35507,6 +35527,8 @@ class BybitExchange {
35507
35527
  }
35508
35528
  async crossAccountTransfer(payload) {
35509
35529
  }
35530
+ async placeMarketOrder(payload) {
35531
+ }
35510
35532
  }
35511
35533
 
35512
35534
  // src/helpers/accounts.ts
@@ -36190,6 +36212,18 @@ function generate_config_params(app_config, payload) {
36190
36212
  risk: payload.risk
36191
36213
  };
36192
36214
  }
36215
+ function determine_break_even_price(payload) {
36216
+ const { long_position, short_position, fee_percent = 0.05 / 100 } = payload;
36217
+ const long_notional = long_position.entry * long_position.quantity;
36218
+ const short_notional = short_position.entry * short_position.quantity;
36219
+ const net_quantity = long_position.quantity - short_position.quantity;
36220
+ const net_capital = Math.abs(long_notional - short_notional);
36221
+ const break_even_price = net_capital / (Math.abs(net_quantity) + fee_percent * Math.abs(net_quantity));
36222
+ return {
36223
+ price: break_even_price,
36224
+ direction: net_quantity > 0 ? "long" : "short"
36225
+ };
36226
+ }
36193
36227
 
36194
36228
  // src/exchange-account.ts
36195
36229
  class ExchangeAccount {
@@ -36371,6 +36405,18 @@ class ExchangeAccount {
36371
36405
  async cancelExchangeOrders(payload) {
36372
36406
  return this.exchange.cancelOrders(payload);
36373
36407
  }
36408
+ async getBreakEvenPrice(payload) {
36409
+ const positions = await this.syncAccount({
36410
+ symbol: payload.symbol
36411
+ });
36412
+ const long_position = positions.find((x) => x.kind === "long");
36413
+ const short_position = positions.find((x) => x.kind === "short");
36414
+ const break_even_price = determine_break_even_price({
36415
+ long_position,
36416
+ short_position
36417
+ });
36418
+ return break_even_price;
36419
+ }
36374
36420
  async buildAppConfig(payload) {
36375
36421
  let config = await this.app_db.getSymbolConfigFromDB(payload.symbol);
36376
36422
  const app_config = buildAppConfig(config, payload);
@@ -36391,6 +36437,58 @@ class ExchangeAccount {
36391
36437
  }
36392
36438
  return app_config;
36393
36439
  }
36440
+ async buildTrades(payload) {
36441
+ const { symbol, kind, risk } = payload;
36442
+ const config = await this.getPositionConfig({
36443
+ symbol,
36444
+ kind
36445
+ });
36446
+ const app_config = await this.buildAppConfig({
36447
+ entry: config.entry,
36448
+ stop: config.stop,
36449
+ risk_reward: config.risk_reward,
36450
+ risk: risk || config.risk,
36451
+ symbol
36452
+ });
36453
+ const { trades } = await this.placeConfigOrders(app_config, {
36454
+ risk_reward: config.risk_reward,
36455
+ entry: config.entry,
36456
+ stop: config.stop,
36457
+ risk_per_trade: risk || config.risk,
36458
+ avg_size: 0,
36459
+ neg_pnl: 0,
36460
+ min_size: app_config.min_size,
36461
+ symbol
36462
+ });
36463
+ const position2 = await this.syncAccount({
36464
+ symbol,
36465
+ kind
36466
+ });
36467
+ const orders_to_place = await this.determineAmountToBuy({
36468
+ orders: trades.map((x) => ({
36469
+ entry: x.entry,
36470
+ quantity: x.quantity
36471
+ })),
36472
+ kind,
36473
+ decimal_places: app_config.decimal_places,
36474
+ price_places: app_config.price_places,
36475
+ symbol
36476
+ });
36477
+ const avg_values = determine_average_entry_and_size(orders_to_place.map((u) => ({
36478
+ price: u.entry,
36479
+ quantity: u.quantity
36480
+ })).concat({
36481
+ price: position2.entry,
36482
+ quantity: position2.quantity
36483
+ }), app_config.decimal_places, app_config.price_places);
36484
+ return {
36485
+ trades: orders_to_place,
36486
+ max_size: trades[0].avg_size,
36487
+ last_price: trades[0].entry,
36488
+ total_size: avg_values.quantity,
36489
+ avg_entry: avg_values.price
36490
+ };
36491
+ }
36394
36492
  async placeConfigOrders(app_config, solution, place, skip_stop) {
36395
36493
  app_config.entry = solution.entry;
36396
36494
  app_config.stop = solution.stop;
@@ -36466,7 +36564,14 @@ class ExchangeAccount {
36466
36564
  };
36467
36565
  }
36468
36566
  async determineAmountToBuy(payload) {
36469
- const { orders, kind, decimal_places = "%.3f", symbol } = payload;
36567
+ const {
36568
+ orders,
36569
+ kind,
36570
+ decimal_places = "%.3f",
36571
+ symbol,
36572
+ refresh,
36573
+ cancel
36574
+ } = payload;
36470
36575
  const totalQuantity = orders.reduce((sum, order) => sum + (order.quantity || 0), 0);
36471
36576
  let runningTotal = to_f(totalQuantity, decimal_places);
36472
36577
  let sortedOrders = [...orders].sort((a, b) => (a.entry || 0) - (b.entry || 0));
@@ -36485,7 +36590,7 @@ class ExchangeAccount {
36485
36590
  const position2 = await this.syncAccount({
36486
36591
  symbol,
36487
36592
  kind,
36488
- live_refresh: true,
36593
+ live_refresh: refresh,
36489
36594
  update: true
36490
36595
  });
36491
36596
  let existingOrders = await this.syncOrders({
@@ -36502,7 +36607,7 @@ class ExchangeAccount {
36502
36607
  filteredOrders = filteredOrders.filter((k) => !existingOrders.map((j) => j.price).includes(k.price));
36503
36608
  const side = kind.toLowerCase() === "long" ? "buy" : "sell";
36504
36609
  const shouldCancel = existingOrders.filter((k) => !orders.map((j) => j.entry).includes(k.price) && k.side === side).map((u) => u.price);
36505
- if (shouldCancel.length > 0) {
36610
+ if (shouldCancel.length > 0 && cancel) {
36506
36611
  const pp = kind === "long" ? Math.max(...shouldCancel) : Math.min(...shouldCancel);
36507
36612
  const cancel_orders = await this.cancelOrders({
36508
36613
  symbol,
@@ -36599,6 +36704,31 @@ class ExchangeAccount {
36599
36704
  stop_orders
36600
36705
  };
36601
36706
  }
36707
+ async getOrCreatePositionConfig(payload) {
36708
+ const { symbol, kind, risk = 50, risk_reward = 199 } = payload;
36709
+ const config = await this.getPositionConfig({
36710
+ symbol: payload.symbol,
36711
+ kind: payload.kind
36712
+ });
36713
+ if (!config) {
36714
+ const long_c = await this.buildConfigForSymbol({
36715
+ symbol,
36716
+ risk,
36717
+ risk_reward
36718
+ });
36719
+ return this.getPositionConfig({
36720
+ symbol,
36721
+ kind,
36722
+ params: {
36723
+ entry: kind === "long" ? long_c.entry : long_c.stop,
36724
+ stop: kind === "long" ? long_c.stop : long_c.entry,
36725
+ risk_reward: long_c.risk_reward,
36726
+ risk: long_c.risk
36727
+ }
36728
+ });
36729
+ }
36730
+ return config;
36731
+ }
36602
36732
  async getPositionConfig(payload) {
36603
36733
  if (payload.params) {
36604
36734
  const db_position = await this.syncAccount({
@@ -36924,8 +37054,44 @@ class ExchangeAccount {
36924
37054
  }
36925
37055
  return null;
36926
37056
  }
37057
+ async placeMarketOrder(payload) {
37058
+ const { symbol, kind, quantity } = payload;
37059
+ const symbol_config = await this.recomputeSymbolConfig({
37060
+ symbol
37061
+ });
37062
+ await this.exchange.placeMarketOrder({
37063
+ symbol,
37064
+ kind,
37065
+ quantity,
37066
+ price_places: symbol_config.price_places,
37067
+ decimal_places: symbol_config.decimal_places
37068
+ });
37069
+ }
37070
+ async placeSingleOrder(payload) {
37071
+ const { symbol, kind } = payload;
37072
+ const positions = await this.syncAccount({
37073
+ live_refresh: true,
37074
+ update: true,
37075
+ symbol
37076
+ });
37077
+ const long_position = positions.find((x) => x.kind === "long");
37078
+ const short_position = positions.find((x) => x.kind === "short");
37079
+ const focus_position = kind === "long" ? long_position : short_position;
37080
+ const track_position = kind === "long" ? short_position : long_position;
37081
+ if (!focus_position.follow) {
37082
+ return "No follow set";
37083
+ }
37084
+ if (track_position.quantity !== focus_position.quantity && focus_position.quantity < track_position.quantity) {
37085
+ const remaining_quantity = Math.abs(track_position.quantity - focus_position.quantity);
37086
+ await this.placeMarketOrder({
37087
+ symbol,
37088
+ kind,
37089
+ quantity: remaining_quantity
37090
+ });
37091
+ }
37092
+ }
36927
37093
  async triggerTradeFromConfig(payload) {
36928
- const { symbol, kind, place = true, stop } = payload;
37094
+ const { symbol, kind, place = true, stop, use_current } = payload;
36929
37095
  const position2 = await this.syncAccount({
36930
37096
  symbol,
36931
37097
  kind
@@ -36942,7 +37108,7 @@ class ExchangeAccount {
36942
37108
  risk: config.risk,
36943
37109
  place,
36944
37110
  raw: payload.raw,
36945
- use_current: Boolean(stop)
37111
+ use_current
36946
37112
  });
36947
37113
  }
36948
37114
  }
@@ -37991,6 +38157,7 @@ class App {
37991
38157
  }
37992
38158
  const positions = await this.app_db.hasExistingPosition(symbol);
37993
38159
  if (positions.length === 0) {
38160
+ console.log("Removing symbol from DB", symbol);
37994
38161
  return this.app_db.unwindSymbolFromDB(symbol);
37995
38162
  }
37996
38163
  const unique_instances = new Set(positions.map((x) => `${x.symbol}-${x.expand.account.owner}-${x.expand.account.exchange}`));
@@ -38074,15 +38241,29 @@ class App {
38074
38241
  owner: exchange.owner,
38075
38242
  exchange: exchange.exchange
38076
38243
  });
38077
- await exchange_account.syncAccount({
38244
+ await exchange_account.placeProfitAndStop({
38078
38245
  symbol,
38079
- update: true,
38080
- live_refresh: true
38246
+ trigger: true,
38247
+ refresh: true
38081
38248
  });
38082
- await exchange_account.placeProfitAndStop({
38249
+ await exchange_account.syncAccount({
38083
38250
  symbol,
38084
- trigger: false
38251
+ update: true
38252
+ });
38253
+ }
38254
+ }
38255
+ async autoFollowPositions() {
38256
+ const positions = await this.app_db.getPositionsToAutoFollow();
38257
+ for (const position2 of positions) {
38258
+ const account = position2.expand.account;
38259
+ console.log("Getting account for ", account.owner, account.exchange);
38260
+ const exchange_account = await this.getExchangeAccount(account);
38261
+ console.log("Placing follow order for ", position2.symbol);
38262
+ const result = await exchange_account.placeSingleOrder({
38263
+ symbol: position2.symbol,
38264
+ kind: position2.kind
38085
38265
  });
38266
+ console.log("result", result);
38086
38267
  }
38087
38268
  }
38088
38269
  async getMoverExchangeInstances() {
@@ -38241,6 +38422,7 @@ export {
38241
38422
  get_app_config_and_max_size,
38242
38423
  getOptimumStopAndRisk,
38243
38424
  generate_config_params,
38425
+ determine_break_even_price,
38244
38426
  determine_average_entry_and_size,
38245
38427
  createArray,
38246
38428
  buildConfig,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-33",
4
+ "version": "0.0.2-36",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",