@gbozee/ultimate 0.0.2-next.7 → 0.0.2-next.70

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.
@@ -9,7 +9,13 @@ function generateArithmetic(payload) {
9
9
  });
10
10
  }
11
11
  function generateGeometric(payload) {
12
- const { margin_range, risk_reward, kind, price_places = "%.1f", percent_change } = payload;
12
+ const {
13
+ margin_range,
14
+ risk_reward,
15
+ kind,
16
+ price_places = "%.1f",
17
+ percent_change
18
+ } = payload;
13
19
  const effectivePercentChange = percent_change ?? Math.abs(margin_range[1] / margin_range[0] - 1) / risk_reward;
14
20
  return Array.from({ length: risk_reward + 1 }, (_, i) => {
15
21
  const price = kind === "long" ? margin_range[1] * Math.pow(1 - effectivePercentChange, i) : margin_range[0] * Math.pow(1 + effectivePercentChange, i);
@@ -31,7 +37,13 @@ function approximateInverseNormal(p) {
31
37
  }
32
38
  }
33
39
  function generateNormal(payload) {
34
- const { margin_range, risk_reward, kind, price_places = "%.1f", stdDevFactor = 6 } = payload;
40
+ const {
41
+ margin_range,
42
+ risk_reward,
43
+ kind,
44
+ price_places = "%.1f",
45
+ stdDevFactor = 6
46
+ } = payload;
35
47
  const mean = (margin_range[0] + margin_range[1]) / 2;
36
48
  const stdDev = Math.abs(margin_range[1] - margin_range[0]) / stdDevFactor;
37
49
  const skew = kind === "long" ? -0.2 : 0.2;
@@ -46,23 +58,45 @@ function generateNormal(payload) {
46
58
  return entries.sort((a, b) => a - b);
47
59
  }
48
60
  function generateExponential(payload) {
49
- const { margin_range, risk_reward, kind, price_places = "%.1f", lambda } = payload;
61
+ const {
62
+ margin_range,
63
+ risk_reward,
64
+ kind,
65
+ price_places = "%.1f",
66
+ lambda,
67
+ reverse = false
68
+ } = payload;
50
69
  const range = Math.abs(margin_range[1] - margin_range[0]);
51
70
  const effectiveLambda = lambda || 2.5;
71
+ const normalizationFactor = 1 - Math.exp(-effectiveLambda);
52
72
  return Array.from({ length: risk_reward + 1 }, (_, i) => {
53
73
  const t = i / risk_reward;
54
- const exponentialProgress = 1 - Math.exp(-effectiveLambda * t);
55
- const price = kind === "long" ? margin_range[1] - range * exponentialProgress : margin_range[0] + range * exponentialProgress;
74
+ const rawProgress = 1 - Math.exp(-effectiveLambda * t);
75
+ const exponentialProgress = rawProgress / normalizationFactor;
76
+ let price = kind === "long" ? margin_range[1] - range * exponentialProgress : margin_range[0] + range * exponentialProgress;
77
+ if (reverse) {
78
+ price = kind === "long" ? margin_range[0] + range * exponentialProgress : margin_range[1] - range * exponentialProgress;
79
+ }
56
80
  return to_f(price, price_places);
57
81
  });
58
82
  }
59
83
  function generateInverseExponential(payload) {
60
- const { margin_range, risk_reward, kind, price_places = "%.1f", curveFactor = 2 } = payload;
84
+ const {
85
+ margin_range,
86
+ risk_reward,
87
+ kind,
88
+ price_places = "%.1f",
89
+ curveFactor = 2,
90
+ reverse = false
91
+ } = payload;
61
92
  const range = Math.abs(margin_range[1] - margin_range[0]);
62
93
  return Array.from({ length: risk_reward + 1 }, (_, i) => {
63
94
  const t = i / risk_reward;
64
95
  const progress = (Math.exp(curveFactor * t) - 1) / (Math.exp(curveFactor) - 1);
65
- const price = kind === "long" ? margin_range[1] - range * progress : margin_range[0] + range * progress;
96
+ let price = kind === "long" ? margin_range[1] - range * progress : margin_range[0] + range * progress;
97
+ if (reverse) {
98
+ price = kind === "long" ? margin_range[0] + range * progress : margin_range[1] - range * progress;
99
+ }
66
100
  return to_f(price, price_places);
67
101
  });
68
102
  }
@@ -91,8 +125,7 @@ function getEntries(params) {
91
125
  margin_range,
92
126
  risk_reward,
93
127
  kind,
94
- price_places,
95
- percent_change: distribution_params?.curveFactor
128
+ price_places
96
129
  });
97
130
  break;
98
131
  case "normal":
@@ -113,6 +146,16 @@ function getEntries(params) {
113
146
  lambda: distribution_params?.lambda
114
147
  });
115
148
  break;
149
+ case "reverse-exponential":
150
+ entries = generateExponential({
151
+ margin_range,
152
+ risk_reward,
153
+ kind,
154
+ price_places,
155
+ lambda: distribution_params?.lambda,
156
+ reverse: true
157
+ });
158
+ break;
116
159
  case "inverse-exponential":
117
160
  entries = generateInverseExponential({
118
161
  margin_range,
@@ -122,12 +165,53 @@ function getEntries(params) {
122
165
  curveFactor: distribution_params?.curveFactor
123
166
  });
124
167
  break;
168
+ case "reverse-inverse-exponential":
169
+ entries = generateInverseExponential({
170
+ margin_range,
171
+ risk_reward,
172
+ kind,
173
+ price_places,
174
+ curveFactor: distribution_params?.curveFactor,
175
+ reverse: true
176
+ });
177
+ break;
178
+ case "lognormal":
179
+ entries = generateLognormal({
180
+ margin_range,
181
+ risk_reward,
182
+ kind,
183
+ price_places,
184
+ stdDevFactor: distribution_params?.stdDevFactor
185
+ });
186
+ break;
125
187
  default:
126
188
  throw new Error(`Unknown distribution type: ${distribution}`);
127
189
  }
128
190
  return entries.sort((a, b) => a - b);
129
191
  }
130
192
  var distributions_default = getEntries;
193
+ function generateLognormal(payload) {
194
+ const {
195
+ margin_range,
196
+ risk_reward,
197
+ kind,
198
+ price_places = "%.1f",
199
+ stdDevFactor = 6
200
+ } = payload;
201
+ const logMin = Math.log(margin_range[0]);
202
+ const logMax = Math.log(margin_range[1]);
203
+ const mean = (logMin + logMax) / 2;
204
+ const stdDev = Math.abs(logMax - logMin) / stdDevFactor;
205
+ const entries = Array.from({ length: risk_reward + 1 }, (_, i) => {
206
+ const p = (i + 0.5) / (risk_reward + 1);
207
+ const z = approximateInverseNormal(p);
208
+ let logPrice = mean + stdDev * z;
209
+ logPrice = Math.max(logMin, Math.min(logMax, logPrice));
210
+ const price = Math.exp(logPrice);
211
+ return to_f(kind === "long" ? Math.min(price, margin_range[1]) : Math.max(price, margin_range[0]), price_places);
212
+ });
213
+ return entries.sort((a, b) => a - b);
214
+ }
131
215
 
132
216
  // src/helpers/optimizations.ts
133
217
  function calculateTheoreticalKelly({
@@ -501,7 +585,7 @@ class Signal {
501
585
  const simple_support = Math.min(current_price, stop_loss);
502
586
  const simple_resistance = Math.max(current_price, stop_loss);
503
587
  const risk_per_trade = risk / this.risk_reward;
504
- const use_progressive = distribution_params.use_progressive || this.use_progressive_risk;
588
+ const use_progressive = distribution_params?.use_progressive || this.use_progressive_risk;
505
589
  const risk_distribution = use_progressive ? {
506
590
  enabled: true,
507
591
  total_risk_budget: risk,
@@ -1296,6 +1380,9 @@ function formatPrice(value2, opts = {}) {
1296
1380
  return formatter.format(value2);
1297
1381
  }
1298
1382
  function to_f(value2, places = "%.1f") {
1383
+ if (!value2) {
1384
+ return null;
1385
+ }
1299
1386
  let v = typeof value2 === "string" ? parseFloat(value2) : value2;
1300
1387
  const formattedValue = places.replace("%.", "").replace("f", "");
1301
1388
  return parseFloat(v.toFixed(parseInt(formattedValue)));
@@ -1654,7 +1741,7 @@ function buildConfig(app_config, {
1654
1741
  min_avg_size = 0,
1655
1742
  distribution,
1656
1743
  distribution_params,
1657
- use_progressive_risk
1744
+ use_progressive_risk = false
1658
1745
  }) {
1659
1746
  let fee = app_config.fee / 100;
1660
1747
  let working_risk = risk || app_config.risk_per_trade;
@@ -1696,7 +1783,7 @@ function buildConfig(app_config, {
1696
1783
  if (!stop) {
1697
1784
  return [];
1698
1785
  }
1699
- const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
1786
+ const condition = true;
1700
1787
  if (kind === "short") {}
1701
1788
  const result = entry === stop ? [] : condition ? instance.build_entry({
1702
1789
  current_price: entry,
@@ -2179,7 +2266,7 @@ function determineOptimumReward(payload) {
2179
2266
  const criterion = app_config.strategy || "quantity";
2180
2267
  const risk_rewards = createArray(low_range, high_range, 1);
2181
2268
  let func = risk_rewards.map((trade_no) => {
2182
- let trades = sortedBuildConfig(app_config, {
2269
+ const pp = {
2183
2270
  take_profit: app_config.take_profit,
2184
2271
  entry: app_config.entry,
2185
2272
  stop: app_config.stop,
@@ -2191,7 +2278,8 @@ function determineOptimumReward(payload) {
2191
2278
  decimal_places: app_config.decimal_places,
2192
2279
  distribution,
2193
2280
  distribution_params: payload.distribution_params
2194
- });
2281
+ };
2282
+ let trades = sortedBuildConfig(app_config, pp);
2195
2283
  let total = 0;
2196
2284
  let max = -Infinity;
2197
2285
  let min = Infinity;
@@ -2282,7 +2370,6 @@ function findIndexByCondition(lst, kind, condition, defaultKey = "neg_pnl") {
2282
2370
  return b.net_diff - a.net_diff;
2283
2371
  }
2284
2372
  });
2285
- console.log("found", sortedFound);
2286
2373
  if (defaultKey === "quantity") {
2287
2374
  return sortedFound[0].index;
2288
2375
  }
@@ -2913,6 +3000,52 @@ function generateDangerousConfig(payload) {
2913
3000
  risk_reward: optimumRiskReward
2914
3001
  };
2915
3002
  }
3003
+ function computeMarginProtection({
3004
+ entry,
3005
+ quantity,
3006
+ tp,
3007
+ stop_loss,
3008
+ avg_price,
3009
+ avg_qty,
3010
+ next_order,
3011
+ base_asset,
3012
+ symbol
3013
+ }) {
3014
+ const pnl = Math.abs(tp.price - entry) * quantity;
3015
+ const loss = Math.abs(avg_price - stop_loss.price) * avg_qty;
3016
+ const margin_position = pnl / Math.abs(next_order - tp.price);
3017
+ const protect_position = loss / Math.abs(stop_loss.price - tp.price);
3018
+ const ideal_protect_position = loss / Math.abs(next_order - stop_loss.price);
3019
+ const places = {
3020
+ BTCUSDT: "%.5f",
3021
+ ETHUSDT: "%.4f",
3022
+ BNBUSDT: "%.3f"
3023
+ };
3024
+ const price_places = {
3025
+ BTCUSDT: "%.2f",
3026
+ ETHUSDT: "%.2f",
3027
+ BNBUSDT: "%.2f"
3028
+ };
3029
+ let quantity_to_place = protect_position;
3030
+ if (base_asset > 0) {
3031
+ let diff = quantity_to_place - base_asset;
3032
+ quantity_to_place = diff;
3033
+ }
3034
+ const payload = {
3035
+ existing_quantity: base_asset,
3036
+ quantity_to_place: to_f(quantity_to_place, places[symbol]),
3037
+ quantity: to_f(margin_position, places[symbol]),
3038
+ price: tp.price,
3039
+ tp: next_order,
3040
+ risk: to_f(pnl, "%.1f"),
3041
+ protect_quantity: to_f(protect_position, places[symbol]),
3042
+ ideal_protect_quantity: to_f(ideal_protect_position, places[symbol]),
3043
+ hedge: to_f(loss, "%.1f"),
3044
+ price_place: price_places[symbol],
3045
+ decimal_place: places[symbol]
3046
+ };
3047
+ return payload;
3048
+ }
2916
3049
  // src/helpers/strategy.ts
2917
3050
  class Strategy {
2918
3051
  position;
@@ -3487,10 +3620,14 @@ function helperFuncToBuildTrades({
3487
3620
  symbol_config,
3488
3621
  app_config_kind,
3489
3622
  appConfig,
3490
- force_exact_risk = true
3623
+ force_exact_risk = true,
3624
+ use_default = false
3491
3625
  }) {
3492
3626
  const risk = custom_b_config.risk * (custom_b_config.risk_factor || 1);
3493
- let result = getRiskReward({
3627
+ let result = use_default ? {
3628
+ risk,
3629
+ risk_reward: custom_b_config.risk_reward
3630
+ } : getRiskReward({
3494
3631
  entry: custom_b_config.entry,
3495
3632
  stop: custom_b_config.stop,
3496
3633
  risk,
@@ -3539,7 +3676,8 @@ function buildWithOptimumReward({
3539
3676
  config,
3540
3677
  settings,
3541
3678
  global_config,
3542
- force_exact
3679
+ force_exact,
3680
+ use_default = false
3543
3681
  }) {
3544
3682
  const kind = config.entry > config.stop ? "long" : "short";
3545
3683
  let stop = settings.stop;
@@ -3553,7 +3691,8 @@ function buildWithOptimumReward({
3553
3691
  stop,
3554
3692
  risk,
3555
3693
  distribution,
3556
- distribution_params
3694
+ distribution_params,
3695
+ risk_reward: settings.risk_reward || config?.risk_reward
3557
3696
  };
3558
3697
  const appConfig = constructAppConfig2({
3559
3698
  config,
@@ -3564,7 +3703,8 @@ function buildWithOptimumReward({
3564
3703
  app_config_kind: kind,
3565
3704
  appConfig,
3566
3705
  symbol_config: global_config,
3567
- force_exact_risk: force_exact
3706
+ force_exact_risk: force_exact,
3707
+ use_default
3568
3708
  });
3569
3709
  const adjusted_size = summary.quantity;
3570
3710
  const symbol_config = global_config;
@@ -3876,6 +4016,351 @@ var compoundAPI = {
3876
4016
  increaseTradeHelper,
3877
4017
  generatePositionIncreaseTrade
3878
4018
  };
4019
+ // src/exchanges/paper/engine-class.ts
4020
+ function generateSummary2({
4021
+ trades = [],
4022
+ fee_percent = 0.05,
4023
+ anchor
4024
+ }) {
4025
+ if (trades.length === 0) {
4026
+ return {};
4027
+ }
4028
+ const avg_entry = trades[0].avg_entry;
4029
+ const avg_size = trades[0].avg_size;
4030
+ const expected_fee = avg_entry * avg_size * fee_percent / 100;
4031
+ return {
4032
+ first_entry: trades.at(-1).entry,
4033
+ last_entry: trades[0].entry,
4034
+ quantity: avg_size,
4035
+ entry: avg_entry,
4036
+ loss: trades[0].neg_pnl,
4037
+ number_of_trades: trades.length,
4038
+ fee: to_f(expected_fee, "%.2f"),
4039
+ anchor_pnl: anchor?.target_pnl
4040
+ };
4041
+ }
4042
+ function cumulativeHelper({
4043
+ tradesList,
4044
+ pos = {
4045
+ quantity: 0,
4046
+ entry: 0
4047
+ },
4048
+ decimal_places = "%.3f"
4049
+ }) {
4050
+ let cumulativeQty = pos.quantity || 0;
4051
+ const reversedTrades = [...tradesList].reverse();
4052
+ const processedTrades = reversedTrades.map((trade) => {
4053
+ cumulativeQty += trade.quantity;
4054
+ const avg_size = to_f(cumulativeQty, decimal_places);
4055
+ return {
4056
+ ...trade,
4057
+ cumulative_size: avg_size
4058
+ };
4059
+ });
4060
+ return processedTrades.reverse();
4061
+ }
4062
+
4063
+ class PositionState {
4064
+ position;
4065
+ trades;
4066
+ take_profit = null;
4067
+ stop_loss = null;
4068
+ entry_fees;
4069
+ fee_percent;
4070
+ global_config;
4071
+ constructor({
4072
+ position: position2,
4073
+ trades,
4074
+ fee_percent = 0,
4075
+ entry_fees = 0,
4076
+ global_config
4077
+ }) {
4078
+ this.position = position2;
4079
+ this.trades = trades ?? [];
4080
+ this.entry_fees = entry_fees ?? 0;
4081
+ this.fee_percent = fee_percent ?? 0;
4082
+ this.global_config = global_config;
4083
+ }
4084
+ get newTrades() {
4085
+ const tradesList = this.trades;
4086
+ const pos = this.position;
4087
+ if (!tradesList || tradesList.length === 0) {
4088
+ return [];
4089
+ }
4090
+ let cumulativeQty = pos.quantity || 0;
4091
+ let cumulativeValue = cumulativeQty * (pos.entry || 0);
4092
+ const reversedTrades = [...tradesList].reverse();
4093
+ const processedTrades = reversedTrades.map((trade) => {
4094
+ cumulativeQty += trade.quantity;
4095
+ cumulativeValue += trade.quantity * trade.entry;
4096
+ const avg_entry = cumulativeQty > 0 ? to_f(cumulativeValue / cumulativeQty, this.global_config.price_places) : 0;
4097
+ const avg_size = to_f(cumulativeQty, this.global_config.decimal_places);
4098
+ const stop = trade.stop || pos.kind === "long" ? Math.min(...tradesList.map((o) => o.entry)) : Math.max(...tradesList.map((o) => o.entry));
4099
+ const neg_pnl = to_f(Math.abs(avg_entry - stop) * avg_size, this.global_config.price_places);
4100
+ return {
4101
+ ...trade,
4102
+ avg_entry,
4103
+ avg_size,
4104
+ neg_pnl
4105
+ };
4106
+ });
4107
+ return processedTrades.reverse();
4108
+ }
4109
+ generateSummary(fee_percentOverride) {
4110
+ const trades = this.newTrades;
4111
+ const fee_percent = fee_percentOverride ?? this.fee_percent;
4112
+ return {
4113
+ ...generateSummary2({
4114
+ trades,
4115
+ fee_percent
4116
+ }),
4117
+ entry_fees: to_f(this.entry_fees, "%.2f")
4118
+ };
4119
+ }
4120
+ get summary() {
4121
+ return this.generateSummary();
4122
+ }
4123
+ positionAt(price) {
4124
+ const trades = this.newTrades;
4125
+ const kind = this.position.kind;
4126
+ const filtered = trades.filter((trade) => {
4127
+ if (kind === "long") {
4128
+ return trade.entry >= price;
4129
+ }
4130
+ return trade.entry <= price;
4131
+ });
4132
+ return filtered[0];
4133
+ }
4134
+ newPositionState(price) {
4135
+ const position2 = this.position;
4136
+ const trades = this.newTrades;
4137
+ const instance = this.positionAt(price);
4138
+ if (!instance) {
4139
+ return new PositionState({
4140
+ position: { ...position2 },
4141
+ trades,
4142
+ fee_percent: this.fee_percent,
4143
+ entry_fees: this.entry_fees,
4144
+ global_config: this.global_config
4145
+ });
4146
+ }
4147
+ return new PositionState({
4148
+ position: {
4149
+ ...position2,
4150
+ entry: instance.avg_entry,
4151
+ quantity: instance.avg_size
4152
+ },
4153
+ trades,
4154
+ fee_percent: this.fee_percent,
4155
+ entry_fees: this.entry_fees,
4156
+ global_config: this.global_config
4157
+ });
4158
+ }
4159
+ updateTakeProfit({ entry, quantity }) {
4160
+ this.take_profit = {
4161
+ price: entry,
4162
+ quantity: quantity ?? this.position.quantity
4163
+ };
4164
+ }
4165
+ updateStopLoss(payload) {
4166
+ const { stop, quantity } = payload ?? {
4167
+ stop: this.newTrades[0].entry,
4168
+ quantity: this.summary.quantity
4169
+ };
4170
+ this.stop_loss = {
4171
+ price: stop,
4172
+ quantity
4173
+ };
4174
+ }
4175
+ }
4176
+ function determineNewPosition({
4177
+ position: position2,
4178
+ price,
4179
+ trades,
4180
+ global_config
4181
+ }) {
4182
+ const kind = position2.kind;
4183
+ const placed = trades.filter((t) => {
4184
+ let _price = t.entry || t.price;
4185
+ let condition1 = kind === "long" ? _price >= price : _price <= price;
4186
+ return condition1;
4187
+ }).map((t) => {
4188
+ let _price = t.entry || t.price;
4189
+ let condition2 = kind === "long" ? _price >= position2.entry : _price <= position2.entry;
4190
+ if (condition2) {
4191
+ return {
4192
+ ...t,
4193
+ price: position2.entry,
4194
+ entry: position2.entry
4195
+ };
4196
+ }
4197
+ return t;
4198
+ });
4199
+ const placeQty = placed.reduce((acc, trade) => acc + trade.quantity, 0);
4200
+ if (position2.quantity > 0) {
4201
+ const placed_less_than_entry = placed.filter((t) => {
4202
+ let condition1 = kind === "long" ? t.entry <= position2.entry : t.entry >= position2.entry;
4203
+ return condition1;
4204
+ });
4205
+ const avg = determine_average_entry_and_size(placed_less_than_entry.map((o) => ({
4206
+ price: o.entry || o.price,
4207
+ quantity: o.quantity
4208
+ })).concat([{ price: position2.entry, quantity: position2.quantity }]), global_config.decimal_places, global_config.price_places);
4209
+ position2.entry = avg.price;
4210
+ position2.quantity = avg.quantity;
4211
+ return position2;
4212
+ }
4213
+ return {
4214
+ ...position2,
4215
+ entry: price,
4216
+ quantity: placeQty
4217
+ };
4218
+ }
4219
+ function positionAt({
4220
+ price,
4221
+ position: position2,
4222
+ trades = [],
4223
+ as_state = true,
4224
+ global_config
4225
+ }) {
4226
+ const kind = position2.kind;
4227
+ const fee_rate = {
4228
+ maker: 0.02,
4229
+ taker: 0.05
4230
+ };
4231
+ const placed = trades.filter((t) => {
4232
+ let _price = t.entry || t.price;
4233
+ let condition1 = kind === "long" ? _price >= price : _price <= price;
4234
+ return condition1;
4235
+ });
4236
+ const not_placed = trades.filter((t) => {
4237
+ let _price = t.entry || t.price;
4238
+ let condition1 = kind === "long" ? _price < price : _price > price;
4239
+ return condition1;
4240
+ });
4241
+ const placeQty = placed.reduce((acc, trade) => acc + trade.quantity, 0);
4242
+ const takerFee = price * placeQty * fee_rate.taker / 100;
4243
+ const makerFee = not_placed.reduce((acc, trade) => acc + trade.entry * trade.quantity * fee_rate.maker / 100, 0);
4244
+ const fee = to_f(takerFee + makerFee, "%.2f");
4245
+ const result = {
4246
+ trades: not_placed,
4247
+ position: determineNewPosition({
4248
+ global_config,
4249
+ position: { ...position2, kind },
4250
+ price,
4251
+ trades
4252
+ }),
4253
+ entry_fees: fee,
4254
+ fee_percent: fee_rate.maker,
4255
+ global_config
4256
+ };
4257
+ if (as_state) {
4258
+ const derivedState = new PositionState({
4259
+ position: result.position,
4260
+ trades: result.trades,
4261
+ fee_percent: result.fee_percent,
4262
+ entry_fees: parseFloat(result.entry_fees) || 0,
4263
+ global_config
4264
+ });
4265
+ return derivedState;
4266
+ }
4267
+ return result;
4268
+ }
4269
+
4270
+ class TradeEngine {
4271
+ trade_details = null;
4272
+ position;
4273
+ global_config;
4274
+ constructor({
4275
+ global_config,
4276
+ position: position2 = { entry: 0, quantity: 0, kind: "long" }
4277
+ }) {
4278
+ this.global_config = global_config;
4279
+ this.position = position2;
4280
+ }
4281
+ generateShortTrades(config) {
4282
+ const result = compoundAPI.buildWithOptimumReward({
4283
+ global_config: this.global_config,
4284
+ config,
4285
+ settings: config,
4286
+ use_default: true
4287
+ });
4288
+ this.trade_details = result;
4289
+ }
4290
+ positionAt({
4291
+ price,
4292
+ dangerous,
4293
+ trades: existingTrades
4294
+ }) {
4295
+ const trades = existingTrades || this.trade_details?.trades || [];
4296
+ if (dangerous) {
4297
+ const kind = this.position.kind;
4298
+ const naive_assumptions = positionAt({
4299
+ price,
4300
+ position: {
4301
+ kind,
4302
+ entry: 0,
4303
+ quantity: 0
4304
+ },
4305
+ global_config: this.global_config,
4306
+ trades,
4307
+ as_state: false
4308
+ });
4309
+ const avg_position = determine_average_entry_and_size([
4310
+ {
4311
+ price: this.position.entry,
4312
+ quantity: this.position.quantity
4313
+ },
4314
+ {
4315
+ price: naive_assumptions.position.entry,
4316
+ quantity: naive_assumptions.position.quantity
4317
+ }
4318
+ ], this.global_config.decimal_places, this.global_config.price_places);
4319
+ const new_position = dangerous ? {
4320
+ ...this.position,
4321
+ entry: avg_position.entry,
4322
+ quantity: avg_position.quantity
4323
+ } : this.position;
4324
+ return new PositionState({
4325
+ ...naive_assumptions,
4326
+ trades: naive_assumptions.trades,
4327
+ position: new_position,
4328
+ global_config: this.global_config
4329
+ });
4330
+ }
4331
+ const _trades = cumulativeHelper({
4332
+ tradesList: [...trades].concat({
4333
+ entry: this.position.entry,
4334
+ quantity: this.position.quantity
4335
+ }),
4336
+ decimal_places: this.global_config.decimal_places
4337
+ }).filter((o) => {
4338
+ const numeric = Number(o.cumulative_size);
4339
+ return numeric > this.position.quantity;
4340
+ });
4341
+ return positionAt({
4342
+ price,
4343
+ position: this.position,
4344
+ trades: _trades,
4345
+ global_config: this.global_config
4346
+ });
4347
+ }
4348
+ initializeEngine({
4349
+ price,
4350
+ dangerous,
4351
+ trades,
4352
+ config
4353
+ }) {
4354
+ if (config) {
4355
+ this.generateShortTrades(config);
4356
+ }
4357
+ return this.positionAt({
4358
+ price,
4359
+ dangerous,
4360
+ trades
4361
+ });
4362
+ }
4363
+ }
3879
4364
  export {
3880
4365
  to_f,
3881
4366
  sortedBuildConfig,
@@ -3904,6 +4389,7 @@ export {
3904
4389
  determine_stop_and_size,
3905
4390
  determine_remaining_entry,
3906
4391
  determine_position_size,
4392
+ determine_pnl,
3907
4393
  determine_break_even_price,
3908
4394
  determine_average_entry_and_size,
3909
4395
  determine_amount_to_sell2 as determine_amount_to_sell,
@@ -3920,6 +4406,7 @@ export {
3920
4406
  computeSellZones,
3921
4407
  computeRiskReward,
3922
4408
  computeProfitDetail,
4409
+ computeMarginProtection,
3923
4410
  compoundAPI,
3924
4411
  calculateFactorFromTakeProfit,
3925
4412
  calculateFactorFromSellQuantity,
@@ -3928,6 +4415,8 @@ export {
3928
4415
  buildAppConfig,
3929
4416
  asCoins,
3930
4417
  allCoins,
4418
+ TradeEngine,
3931
4419
  Strategy,
3932
- SpecialCoins
4420
+ SpecialCoins,
4421
+ Signal
3933
4422
  };