@gbozee/ultimate 0.0.2-next.8 → 0.0.2-next.80

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
  }
@@ -112,6 +146,16 @@ function getEntries(params) {
112
146
  lambda: distribution_params?.lambda
113
147
  });
114
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;
115
159
  case "inverse-exponential":
116
160
  entries = generateInverseExponential({
117
161
  margin_range,
@@ -121,12 +165,53 @@ function getEntries(params) {
121
165
  curveFactor: distribution_params?.curveFactor
122
166
  });
123
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;
124
187
  default:
125
188
  throw new Error(`Unknown distribution type: ${distribution}`);
126
189
  }
127
190
  return entries.sort((a, b) => a - b);
128
191
  }
129
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
+ }
130
215
 
131
216
  // src/helpers/optimizations.ts
132
217
  function calculateTheoreticalKelly({
@@ -500,7 +585,7 @@ class Signal {
500
585
  const simple_support = Math.min(current_price, stop_loss);
501
586
  const simple_resistance = Math.max(current_price, stop_loss);
502
587
  const risk_per_trade = risk / this.risk_reward;
503
- const use_progressive = distribution_params.use_progressive || this.use_progressive_risk;
588
+ const use_progressive = distribution_params?.use_progressive || this.use_progressive_risk;
504
589
  const risk_distribution = use_progressive ? {
505
590
  enabled: true,
506
591
  total_risk_budget: risk,
@@ -1295,6 +1380,9 @@ function formatPrice(value2, opts = {}) {
1295
1380
  return formatter.format(value2);
1296
1381
  }
1297
1382
  function to_f(value2, places = "%.1f") {
1383
+ if (!value2) {
1384
+ return null;
1385
+ }
1298
1386
  let v = typeof value2 === "string" ? parseFloat(value2) : value2;
1299
1387
  const formattedValue = places.replace("%.", "").replace("f", "");
1300
1388
  return parseFloat(v.toFixed(parseInt(formattedValue)));
@@ -1653,7 +1741,7 @@ function buildConfig(app_config, {
1653
1741
  min_avg_size = 0,
1654
1742
  distribution,
1655
1743
  distribution_params,
1656
- use_progressive_risk
1744
+ use_progressive_risk = false
1657
1745
  }) {
1658
1746
  let fee = app_config.fee / 100;
1659
1747
  let working_risk = risk || app_config.risk_per_trade;
@@ -1695,7 +1783,7 @@ function buildConfig(app_config, {
1695
1783
  if (!stop) {
1696
1784
  return [];
1697
1785
  }
1698
- const condition = (kind === "long" ? entry > app_config.support : entry >= app_config.support) && stop >= app_config.support * 0.999;
1786
+ const condition = true;
1699
1787
  if (kind === "short") {}
1700
1788
  const result = entry === stop ? [] : condition ? instance.build_entry({
1701
1789
  current_price: entry,
@@ -2178,7 +2266,7 @@ function determineOptimumReward(payload) {
2178
2266
  const criterion = app_config.strategy || "quantity";
2179
2267
  const risk_rewards = createArray(low_range, high_range, 1);
2180
2268
  let func = risk_rewards.map((trade_no) => {
2181
- let trades = sortedBuildConfig(app_config, {
2269
+ const pp = {
2182
2270
  take_profit: app_config.take_profit,
2183
2271
  entry: app_config.entry,
2184
2272
  stop: app_config.stop,
@@ -2190,7 +2278,8 @@ function determineOptimumReward(payload) {
2190
2278
  decimal_places: app_config.decimal_places,
2191
2279
  distribution,
2192
2280
  distribution_params: payload.distribution_params
2193
- });
2281
+ };
2282
+ let trades = sortedBuildConfig(app_config, pp);
2194
2283
  let total = 0;
2195
2284
  let max = -Infinity;
2196
2285
  let min = Infinity;
@@ -2281,7 +2370,6 @@ function findIndexByCondition(lst, kind, condition, defaultKey = "neg_pnl") {
2281
2370
  return b.net_diff - a.net_diff;
2282
2371
  }
2283
2372
  });
2284
- console.log("found", sortedFound);
2285
2373
  if (defaultKey === "quantity") {
2286
2374
  return sortedFound[0].index;
2287
2375
  }
@@ -2912,6 +3000,52 @@ function generateDangerousConfig(payload) {
2912
3000
  risk_reward: optimumRiskReward
2913
3001
  };
2914
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
+ }
2915
3049
  // src/helpers/strategy.ts
2916
3050
  class Strategy {
2917
3051
  position;
@@ -3486,10 +3620,14 @@ function helperFuncToBuildTrades({
3486
3620
  symbol_config,
3487
3621
  app_config_kind,
3488
3622
  appConfig,
3489
- force_exact_risk = true
3623
+ force_exact_risk = true,
3624
+ use_default = false
3490
3625
  }) {
3491
3626
  const risk = custom_b_config.risk * (custom_b_config.risk_factor || 1);
3492
- let result = getRiskReward({
3627
+ let result = use_default ? {
3628
+ risk,
3629
+ risk_reward: custom_b_config.risk_reward
3630
+ } : getRiskReward({
3493
3631
  entry: custom_b_config.entry,
3494
3632
  stop: custom_b_config.stop,
3495
3633
  risk,
@@ -3538,7 +3676,8 @@ function buildWithOptimumReward({
3538
3676
  config,
3539
3677
  settings,
3540
3678
  global_config,
3541
- force_exact
3679
+ force_exact,
3680
+ use_default = false
3542
3681
  }) {
3543
3682
  const kind = config.entry > config.stop ? "long" : "short";
3544
3683
  let stop = settings.stop;
@@ -3552,7 +3691,8 @@ function buildWithOptimumReward({
3552
3691
  stop,
3553
3692
  risk,
3554
3693
  distribution,
3555
- distribution_params
3694
+ distribution_params,
3695
+ risk_reward: settings.risk_reward || config?.risk_reward
3556
3696
  };
3557
3697
  const appConfig = constructAppConfig2({
3558
3698
  config,
@@ -3563,7 +3703,8 @@ function buildWithOptimumReward({
3563
3703
  app_config_kind: kind,
3564
3704
  appConfig,
3565
3705
  symbol_config: global_config,
3566
- force_exact_risk: force_exact
3706
+ force_exact_risk: force_exact,
3707
+ use_default
3567
3708
  });
3568
3709
  const adjusted_size = summary.quantity;
3569
3710
  const symbol_config = global_config;
@@ -3875,6 +4016,351 @@ var compoundAPI = {
3875
4016
  increaseTradeHelper,
3876
4017
  generatePositionIncreaseTrade
3877
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
+ }
3878
4364
  export {
3879
4365
  to_f,
3880
4366
  sortedBuildConfig,
@@ -3903,6 +4389,7 @@ export {
3903
4389
  determine_stop_and_size,
3904
4390
  determine_remaining_entry,
3905
4391
  determine_position_size,
4392
+ determine_pnl,
3906
4393
  determine_break_even_price,
3907
4394
  determine_average_entry_and_size,
3908
4395
  determine_amount_to_sell2 as determine_amount_to_sell,
@@ -3919,6 +4406,7 @@ export {
3919
4406
  computeSellZones,
3920
4407
  computeRiskReward,
3921
4408
  computeProfitDetail,
4409
+ computeMarginProtection,
3922
4410
  compoundAPI,
3923
4411
  calculateFactorFromTakeProfit,
3924
4412
  calculateFactorFromSellQuantity,
@@ -3927,6 +4415,8 @@ export {
3927
4415
  buildAppConfig,
3928
4416
  asCoins,
3929
4417
  allCoins,
4418
+ TradeEngine,
3930
4419
  Strategy,
3931
- SpecialCoins
4420
+ SpecialCoins,
4421
+ Signal
3932
4422
  };