shufflecom-calculations 6.11.0 → 6.12.0
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/lib/games/stonks/constants.d.ts +21 -0
- package/lib/games/stonks/constants.js +28 -0
- package/lib/games/stonks/constants.js.map +1 -0
- package/lib/games/stonks/rng/index.d.ts +2 -0
- package/lib/games/stonks/rng/index.js +8 -0
- package/lib/games/stonks/rng/index.js.map +1 -0
- package/lib/games/stonks/rng/shuffle-stonks-rng.d.ts +2 -0
- package/lib/games/{rollercoaster/rng/shuffle-rollercoaster-rng.js → stonks/rng/shuffle-stonks-rng.js} +5 -5
- package/lib/games/stonks/rng/shuffle-stonks-rng.js.map +1 -0
- package/lib/games/stonks/rng/stonks-price-calculator.d.ts +21 -0
- package/lib/games/{rollercoaster/rng/rollercoaster-price-calculator.js → stonks/rng/stonks-price-calculator.js} +12 -12
- package/lib/games/stonks/rng/stonks-price-calculator.js.map +1 -0
- package/lib/games/{rollercoaster/rollercoaster-rules.d.ts → stonks/stonks-rules.d.ts} +25 -25
- package/lib/games/stonks/stonks-rules.js +146 -0
- package/lib/games/stonks/stonks-rules.js.map +1 -0
- package/lib/index.d.ts +3 -3
- package/lib/index.js +3 -3
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/games/stonks/constants.ts +44 -0
- package/src/games/stonks/rng/index.ts +7 -0
- package/src/games/{rollercoaster/rng/shuffle-rollercoaster-rng.spec.ts → stonks/rng/shuffle-stonks-rng.spec.ts} +5 -5
- package/src/games/{rollercoaster/rng/shuffle-rollercoaster-rng.ts → stonks/rng/shuffle-stonks-rng.ts} +6 -6
- package/src/games/{rollercoaster/rng/rollercoaster-price-calculator.spec.ts → stonks/rng/stonks-price-calculator.spec.ts} +12 -12
- package/src/games/{rollercoaster/rng/rollercoaster-price-calculator.ts → stonks/rng/stonks-price-calculator.ts} +19 -19
- package/src/games/stonks/stonks-rules.spec.ts +348 -0
- package/src/games/stonks/stonks-rules.ts +217 -0
- package/src/index.ts +3 -3
- package/lib/games/rollercoaster/constants.d.ts +0 -21
- package/lib/games/rollercoaster/constants.js +0 -28
- package/lib/games/rollercoaster/constants.js.map +0 -1
- package/lib/games/rollercoaster/rng/index.d.ts +0 -2
- package/lib/games/rollercoaster/rng/index.js +0 -8
- package/lib/games/rollercoaster/rng/index.js.map +0 -1
- package/lib/games/rollercoaster/rng/rollercoaster-price-calculator.d.ts +0 -21
- package/lib/games/rollercoaster/rng/rollercoaster-price-calculator.js.map +0 -1
- package/lib/games/rollercoaster/rng/shuffle-rollercoaster-rng.d.ts +0 -2
- package/lib/games/rollercoaster/rng/shuffle-rollercoaster-rng.js.map +0 -1
- package/lib/games/rollercoaster/rollercoaster-rules.js +0 -146
- package/lib/games/rollercoaster/rollercoaster-rules.js.map +0 -1
- package/src/games/rollercoaster/constants.ts +0 -44
- package/src/games/rollercoaster/rng/index.ts +0 -7
- package/src/games/rollercoaster/rollercoaster-rules.spec.ts +0 -348
- package/src/games/rollercoaster/rollercoaster-rules.ts +0 -217
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import BigNumber from 'bignumber.js';
|
|
2
|
+
import { calculatePayoutBN } from '../../utils/calculate-payout';
|
|
3
|
+
import {
|
|
4
|
+
STONKS_INTERNAL_PRICE_DECIMAL_PLACES,
|
|
5
|
+
STONKS_MAX_STALE_CLIENT_TICKS,
|
|
6
|
+
STONKS_MIN_TAKE_PROFIT_MULTIPLIER,
|
|
7
|
+
STONKS_PROFIT_FEE_RATE,
|
|
8
|
+
STONKS_ROUND_DURATION_MS,
|
|
9
|
+
STONKS_ROUND_TICK_COUNT,
|
|
10
|
+
STONKS_TICK_DURATION_MS,
|
|
11
|
+
STONKS_TP_MIN_PROXIMITY_TO_BUST,
|
|
12
|
+
STONKS_TP_MIN_PROXIMITY_TO_ENTRY,
|
|
13
|
+
} from './constants';
|
|
14
|
+
|
|
15
|
+
export enum StonksDirection {
|
|
16
|
+
UP = 'UP',
|
|
17
|
+
DOWN = 'DOWN',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export enum StonksBetTerminalReason {
|
|
21
|
+
CASHOUT = 'CASHOUT',
|
|
22
|
+
TAKE_PROFIT = 'TAKE_PROFIT',
|
|
23
|
+
LIQUIDATION = 'LIQUIDATION',
|
|
24
|
+
MAX_PAYOUT = 'MAX_PAYOUT',
|
|
25
|
+
ROUND_END = 'ROUND_END',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface StonksOpenBetState {
|
|
29
|
+
readonly direction: StonksDirection;
|
|
30
|
+
readonly amount: BigNumber;
|
|
31
|
+
readonly leverage: BigNumber;
|
|
32
|
+
readonly entryPrice: BigNumber;
|
|
33
|
+
readonly entryTick: number;
|
|
34
|
+
readonly bustPrice: BigNumber;
|
|
35
|
+
readonly takeProfitMultiplier: BigNumber | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface StonksTerminalBetState extends StonksOpenBetState {
|
|
39
|
+
readonly terminalReason: StonksBetTerminalReason;
|
|
40
|
+
readonly terminalTick: number;
|
|
41
|
+
readonly terminalPrice: BigNumber;
|
|
42
|
+
readonly multiplier: BigNumber;
|
|
43
|
+
readonly grossPayout: BigNumber;
|
|
44
|
+
readonly netPayout: BigNumber;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type StonksSettlementReason =
|
|
48
|
+
| { kind: StonksBetTerminalReason.CASHOUT }
|
|
49
|
+
| { kind: StonksBetTerminalReason.TAKE_PROFIT; takeProfitMultiplier: BigNumber }
|
|
50
|
+
| { kind: StonksBetTerminalReason.LIQUIDATION }
|
|
51
|
+
| { kind: StonksBetTerminalReason.MAX_PAYOUT; appliedCap: BigNumber }
|
|
52
|
+
| { kind: StonksBetTerminalReason.ROUND_END };
|
|
53
|
+
|
|
54
|
+
export type StonksTriggerOutcome = { fired: false } | { fired: true; reason: StonksSettlementReason };
|
|
55
|
+
|
|
56
|
+
export class StonksRules {
|
|
57
|
+
static bustPrice(entryPrice: BigNumber, leverage: BigNumber, direction: StonksDirection): BigNumber {
|
|
58
|
+
const offset = entryPrice.dividedBy(leverage);
|
|
59
|
+
return direction === StonksDirection.UP ? entryPrice.minus(offset) : entryPrice.plus(offset);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static position(amount: BigNumber, leverage: BigNumber, direction: StonksDirection): BigNumber {
|
|
63
|
+
const magnitude = amount.multipliedBy(leverage);
|
|
64
|
+
return direction === StonksDirection.UP ? magnitude : magnitude.negated();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static impliedPriceForMultiplier(
|
|
68
|
+
bet: Pick<StonksOpenBetState, 'leverage' | 'entryPrice' | 'direction'>,
|
|
69
|
+
targetMultiplier: BigNumber,
|
|
70
|
+
): BigNumber {
|
|
71
|
+
const directionSign = bet.direction === StonksDirection.UP ? 1 : -1;
|
|
72
|
+
const multiplierDelta = targetMultiplier.minus(1);
|
|
73
|
+
const priceChange = BigNumber(directionSign).multipliedBy(multiplierDelta).dividedBy(bet.leverage);
|
|
74
|
+
return bet.entryPrice.multipliedBy(BigNumber(1).plus(priceChange));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static isValidTakeProfitMultiplier(takeProfitMultiplier: BigNumber): boolean {
|
|
78
|
+
return takeProfitMultiplier.isGreaterThan(STONKS_MIN_TAKE_PROFIT_MULTIPLIER);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static isTakeProfitFarEnoughFromEntry(entryPrice: BigNumber, takeProfitImpliedPrice: BigNumber): boolean {
|
|
82
|
+
return takeProfitImpliedPrice.minus(entryPrice).abs().dividedBy(entryPrice).isGreaterThanOrEqualTo(STONKS_TP_MIN_PROXIMITY_TO_ENTRY);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static isTakeProfitFarEnoughFromBust(entryPrice: BigNumber, bustPrice: BigNumber, takeProfitImpliedPrice: BigNumber): boolean {
|
|
86
|
+
return takeProfitImpliedPrice.minus(bustPrice).abs().dividedBy(entryPrice).isGreaterThanOrEqualTo(STONKS_TP_MIN_PROXIMITY_TO_BUST);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static isBustPriceDistinctFromEntry(entryPrice: BigNumber, bustPrice: BigNumber): boolean {
|
|
90
|
+
return !entryPrice
|
|
91
|
+
.decimalPlaces(STONKS_INTERNAL_PRICE_DECIMAL_PLACES)
|
|
92
|
+
.isEqualTo(bustPrice.decimalPlaces(STONKS_INTERNAL_PRICE_DECIMAL_PLACES));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static isFinalTick(activeTick: number): boolean {
|
|
96
|
+
return activeTick >= STONKS_ROUND_TICK_COUNT - 1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static isClientTickWithinMaxLag(activeTick: number, lastSeenTick: number): boolean {
|
|
100
|
+
return activeTick - lastSeenTick <= STONKS_MAX_STALE_CLIENT_TICKS;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static getScheduledRoundId(now: Date, epochMs: number): number {
|
|
104
|
+
return Math.floor((now.getTime() - epochMs) / STONKS_ROUND_DURATION_MS);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static getScheduledRoundStartTime(roundId: number, epochMs: number): Date {
|
|
108
|
+
return new Date(epochMs + roundId * STONKS_ROUND_DURATION_MS);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Tick N occupies [startedAt + N * STONKS_TICK_DURATION_MS, startedAt + (N + 1) * STONKS_TICK_DURATION_MS).
|
|
112
|
+
// tickAtOrAfter is the first tick starting at or after the instant; tickBefore is the last tick
|
|
113
|
+
// starting strictly before it. The two differ only on an exact tick boundary, which is the whole
|
|
114
|
+
// reason both exist rather than one caller-local `Math.ceil(...) - 1`.
|
|
115
|
+
static tickAtOrAfter(startedAtMs: number, atMs: number): number {
|
|
116
|
+
return Math.ceil((atMs - startedAtMs) / STONKS_TICK_DURATION_MS);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static tickBefore(startedAtMs: number, atMs: number): number {
|
|
120
|
+
return StonksRules.tickAtOrAfter(startedAtMs, atMs) - 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static tickStartTime(startedAtMs: number, tick: number): Date {
|
|
124
|
+
return new Date(startedAtMs + tick * STONKS_TICK_DURATION_MS);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static hasReachedTargetPrice(direction: StonksDirection, currentPrice: BigNumber, targetPrice: BigNumber): boolean {
|
|
128
|
+
return direction === StonksDirection.UP ? currentPrice.isGreaterThanOrEqualTo(targetPrice) : currentPrice.isLessThanOrEqualTo(targetPrice);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static hasReachedBust(direction: StonksDirection, price: BigNumber, bustPrice: BigNumber): boolean {
|
|
132
|
+
return direction === StonksDirection.UP ? price.isLessThanOrEqualTo(bustPrice) : price.isGreaterThanOrEqualTo(bustPrice);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static evaluateTriggers(bet: StonksOpenBetState, tickPrice: BigNumber, liveMaxPayoutCap: BigNumber): StonksTriggerOutcome {
|
|
136
|
+
const hitBust = StonksRules.hasReachedBust(bet.direction, tickPrice, bet.bustPrice);
|
|
137
|
+
|
|
138
|
+
if (bet.takeProfitMultiplier != null) {
|
|
139
|
+
const takeProfitMultiplier = bet.takeProfitMultiplier;
|
|
140
|
+
const hitTakeProfit = StonksRules.hasReachedTargetPrice(
|
|
141
|
+
bet.direction,
|
|
142
|
+
tickPrice,
|
|
143
|
+
StonksRules.impliedPriceForMultiplier(bet, takeProfitMultiplier),
|
|
144
|
+
);
|
|
145
|
+
if (hitTakeProfit && hitBust) {
|
|
146
|
+
throw new Error('StonksRules.evaluateTriggers: take profit and liquidation both fired');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (hitTakeProfit) {
|
|
150
|
+
const reason = { kind: StonksBetTerminalReason.TAKE_PROFIT, takeProfitMultiplier } as const;
|
|
151
|
+
// A take-profit is the one reason whose payout is a fixed wager × multiplier rather than
|
|
152
|
+
// something the tick price bounds, and the cap is read live every batch — so it can be
|
|
153
|
+
// lowered under an already-agreed multiplier. Nothing downstream re-checks it.
|
|
154
|
+
if (StonksRules.grossPayoutForReason(bet, reason, tickPrice).isGreaterThan(liveMaxPayoutCap)) {
|
|
155
|
+
return { fired: true, reason: { kind: StonksBetTerminalReason.MAX_PAYOUT, appliedCap: liveMaxPayoutCap } };
|
|
156
|
+
}
|
|
157
|
+
return { fired: true, reason };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (hitBust) {
|
|
162
|
+
return { fired: true, reason: { kind: StonksBetTerminalReason.LIQUIDATION } };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (StonksRules.grossPayoutAtPrice(bet, tickPrice).isGreaterThanOrEqualTo(liveMaxPayoutCap)) {
|
|
166
|
+
return { fired: true, reason: { kind: StonksBetTerminalReason.MAX_PAYOUT, appliedCap: liveMaxPayoutCap } };
|
|
167
|
+
}
|
|
168
|
+
return { fired: false };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static multiplierAtPrice(bet: StonksOpenBetState, price: BigNumber): BigNumber {
|
|
172
|
+
const directionSign = bet.direction === StonksDirection.UP ? 1 : -1;
|
|
173
|
+
const percentagePriceChange = price.minus(bet.entryPrice).dividedBy(bet.entryPrice);
|
|
174
|
+
const leveragedPriceChange = BigNumber(directionSign).multipliedBy(bet.leverage).multipliedBy(percentagePriceChange);
|
|
175
|
+
|
|
176
|
+
const multiplier = BigNumber(1).plus(leveragedPriceChange);
|
|
177
|
+
return BigNumber.maximum(0, multiplier);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static grossPayoutAtPrice(bet: StonksOpenBetState, price: BigNumber): BigNumber {
|
|
181
|
+
const position = StonksRules.position(bet.amount, bet.leverage, bet.direction);
|
|
182
|
+
const pnl = position.multipliedBy(price.minus(bet.entryPrice)).dividedBy(bet.entryPrice);
|
|
183
|
+
return BigNumber.maximum(0, bet.amount.plus(pnl));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
static grossPayoutForReason(bet: StonksOpenBetState, reason: StonksSettlementReason, price: BigNumber): BigNumber {
|
|
187
|
+
switch (reason.kind) {
|
|
188
|
+
case StonksBetTerminalReason.TAKE_PROFIT:
|
|
189
|
+
return calculatePayoutBN(bet.amount, reason.takeProfitMultiplier);
|
|
190
|
+
case StonksBetTerminalReason.LIQUIDATION:
|
|
191
|
+
return BigNumber(0);
|
|
192
|
+
case StonksBetTerminalReason.MAX_PAYOUT:
|
|
193
|
+
return reason.appliedCap;
|
|
194
|
+
case StonksBetTerminalReason.CASHOUT:
|
|
195
|
+
case StonksBetTerminalReason.ROUND_END:
|
|
196
|
+
return StonksRules.grossPayoutAtPrice(bet, price);
|
|
197
|
+
default:
|
|
198
|
+
reason satisfies never;
|
|
199
|
+
throw new Error(`StonksRules.grossPayoutForReason: unhandled reason`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static multiplierForReason(bet: StonksOpenBetState, reason: StonksSettlementReason, price: BigNumber): BigNumber {
|
|
204
|
+
if (reason.kind === StonksBetTerminalReason.TAKE_PROFIT) {
|
|
205
|
+
return reason.takeProfitMultiplier;
|
|
206
|
+
}
|
|
207
|
+
return StonksRules.multiplierAtPrice(bet, price);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
static netPayout(grossPayout: BigNumber, amount: BigNumber): BigNumber {
|
|
211
|
+
if (grossPayout.lte(amount)) {
|
|
212
|
+
return grossPayout;
|
|
213
|
+
}
|
|
214
|
+
const profit = grossPayout.minus(amount);
|
|
215
|
+
return amount.plus(profit.multipliedBy(BigNumber(1).minus(STONKS_PROFIT_FEE_RATE)));
|
|
216
|
+
}
|
|
217
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -63,6 +63,6 @@ export * from './games/rng/shuffle-random-number-generator';
|
|
|
63
63
|
export * from './games/rng/random-number-generator.interface';
|
|
64
64
|
export * from './games/rng/true-random-rng';
|
|
65
65
|
export * from './games/rng/fixed-rng';
|
|
66
|
-
export * from './games/
|
|
67
|
-
export * from './games/
|
|
68
|
-
export * from './games/
|
|
66
|
+
export * from './games/stonks/stonks-rules';
|
|
67
|
+
export * from './games/stonks/constants';
|
|
68
|
+
export * from './games/stonks/rng';
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import BigNumber from 'bignumber.js';
|
|
2
|
-
export declare const ROLLERCOASTER_MIN_TAKE_PROFIT_MULTIPLIER: BigNumber;
|
|
3
|
-
export declare const ROLLERCOASTER_TP_MIN_PROXIMITY_TO_ENTRY: BigNumber;
|
|
4
|
-
export declare const ROLLERCOASTER_TP_MIN_PROXIMITY_TO_BUST: BigNumber;
|
|
5
|
-
export declare const ROLLERCOASTER_INTERNAL_PRICE_DECIMAL_PLACES = 10;
|
|
6
|
-
export declare const ROLLERCOASTER_MIN_LEVERAGE: BigNumber;
|
|
7
|
-
export declare const ROLLERCOASTER_MAX_LEVERAGE: BigNumber;
|
|
8
|
-
export declare const ROLLERCOASTER_MAX_ACTIVE_BETS_PER_ACCOUNT = 20;
|
|
9
|
-
export declare const ROLLERCOASTER_START_PRICE: BigNumber;
|
|
10
|
-
export declare const ROLLERCOASTER_VOLATILITY = 0.001;
|
|
11
|
-
export declare const ROLLERCOASTER_PRICE_DECIMAL_PLACES = 10;
|
|
12
|
-
export declare const ROLLERCOASTER_TICK_DURATION_MS = 500;
|
|
13
|
-
export declare const ROLLERCOASTER_SET_TICK_RETRY_DELAY_MS = 400;
|
|
14
|
-
export declare const ROLLERCOASTER_MAX_STALE_CLIENT_TICKS = 10;
|
|
15
|
-
export declare const ROLLERCOASTER_ROUND_DURATION_MS: number;
|
|
16
|
-
export declare const ROLLERCOASTER_ROUND_TICK_COUNT: number;
|
|
17
|
-
export declare const ROLLERCOASTER_MAX_TICK_HISTORY_MS: number;
|
|
18
|
-
export declare const ROLLERCOASTER_CHECKPOINT_INTERVAL_TICKS = 500;
|
|
19
|
-
export declare const ROLLERCOASTER_PRICE_BAR_INTERVAL_TICKS: number;
|
|
20
|
-
export declare const ROLLERCOASTER_PROFIT_FEE_RATE: BigNumber;
|
|
21
|
-
export declare const ROLLERCOASTER_CONTRACT_SCALE: BigNumber;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ROLLERCOASTER_CONTRACT_SCALE = exports.ROLLERCOASTER_PROFIT_FEE_RATE = exports.ROLLERCOASTER_PRICE_BAR_INTERVAL_TICKS = exports.ROLLERCOASTER_CHECKPOINT_INTERVAL_TICKS = exports.ROLLERCOASTER_MAX_TICK_HISTORY_MS = exports.ROLLERCOASTER_ROUND_TICK_COUNT = exports.ROLLERCOASTER_ROUND_DURATION_MS = exports.ROLLERCOASTER_MAX_STALE_CLIENT_TICKS = exports.ROLLERCOASTER_SET_TICK_RETRY_DELAY_MS = exports.ROLLERCOASTER_TICK_DURATION_MS = exports.ROLLERCOASTER_PRICE_DECIMAL_PLACES = exports.ROLLERCOASTER_VOLATILITY = exports.ROLLERCOASTER_START_PRICE = exports.ROLLERCOASTER_MAX_ACTIVE_BETS_PER_ACCOUNT = exports.ROLLERCOASTER_MAX_LEVERAGE = exports.ROLLERCOASTER_MIN_LEVERAGE = exports.ROLLERCOASTER_INTERNAL_PRICE_DECIMAL_PLACES = exports.ROLLERCOASTER_TP_MIN_PROXIMITY_TO_BUST = exports.ROLLERCOASTER_TP_MIN_PROXIMITY_TO_ENTRY = exports.ROLLERCOASTER_MIN_TAKE_PROFIT_MULTIPLIER = void 0;
|
|
7
|
-
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
8
|
-
exports.ROLLERCOASTER_MIN_TAKE_PROFIT_MULTIPLIER = (0, bignumber_js_1.default)(1.05);
|
|
9
|
-
exports.ROLLERCOASTER_TP_MIN_PROXIMITY_TO_ENTRY = (0, bignumber_js_1.default)(0.001);
|
|
10
|
-
exports.ROLLERCOASTER_TP_MIN_PROXIMITY_TO_BUST = (0, bignumber_js_1.default)(0.001);
|
|
11
|
-
exports.ROLLERCOASTER_INTERNAL_PRICE_DECIMAL_PLACES = 10;
|
|
12
|
-
exports.ROLLERCOASTER_MIN_LEVERAGE = (0, bignumber_js_1.default)(1);
|
|
13
|
-
exports.ROLLERCOASTER_MAX_LEVERAGE = (0, bignumber_js_1.default)(1000);
|
|
14
|
-
exports.ROLLERCOASTER_MAX_ACTIVE_BETS_PER_ACCOUNT = 20;
|
|
15
|
-
exports.ROLLERCOASTER_START_PRICE = (0, bignumber_js_1.default)(1000);
|
|
16
|
-
exports.ROLLERCOASTER_VOLATILITY = 0.001;
|
|
17
|
-
exports.ROLLERCOASTER_PRICE_DECIMAL_PLACES = 10;
|
|
18
|
-
exports.ROLLERCOASTER_TICK_DURATION_MS = 500;
|
|
19
|
-
exports.ROLLERCOASTER_SET_TICK_RETRY_DELAY_MS = 400;
|
|
20
|
-
exports.ROLLERCOASTER_MAX_STALE_CLIENT_TICKS = 10;
|
|
21
|
-
exports.ROLLERCOASTER_ROUND_DURATION_MS = 24 * 60 * 60 * 1000;
|
|
22
|
-
exports.ROLLERCOASTER_ROUND_TICK_COUNT = exports.ROLLERCOASTER_ROUND_DURATION_MS / exports.ROLLERCOASTER_TICK_DURATION_MS;
|
|
23
|
-
exports.ROLLERCOASTER_MAX_TICK_HISTORY_MS = 48 * 60 * 60 * 1000;
|
|
24
|
-
exports.ROLLERCOASTER_CHECKPOINT_INTERVAL_TICKS = 500;
|
|
25
|
-
exports.ROLLERCOASTER_PRICE_BAR_INTERVAL_TICKS = 5000 / exports.ROLLERCOASTER_TICK_DURATION_MS;
|
|
26
|
-
exports.ROLLERCOASTER_PROFIT_FEE_RATE = (0, bignumber_js_1.default)(0.05);
|
|
27
|
-
exports.ROLLERCOASTER_CONTRACT_SCALE = (0, bignumber_js_1.default)(10).pow(6);
|
|
28
|
-
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/games/rollercoaster/constants.ts"],"names":[],"mappings":";;;;;;AAAA,gEAAqC;AAExB,QAAA,wCAAwC,GAAG,IAAA,sBAAS,EAAC,IAAI,CAAC,CAAC;AAE3D,QAAA,uCAAuC,GAAG,IAAA,sBAAS,EAAC,KAAK,CAAC,CAAC;AAC3D,QAAA,sCAAsC,GAAG,IAAA,sBAAS,EAAC,KAAK,CAAC,CAAC;AAI1D,QAAA,2CAA2C,GAAG,EAAE,CAAC;AAGjD,QAAA,0BAA0B,GAAG,IAAA,sBAAS,EAAC,CAAC,CAAC,CAAC;AAC1C,QAAA,0BAA0B,GAAG,IAAA,sBAAS,EAAC,IAAI,CAAC,CAAC;AAE7C,QAAA,yCAAyC,GAAG,EAAE,CAAC;AAE/C,QAAA,yBAAyB,GAAG,IAAA,sBAAS,EAAC,IAAI,CAAC,CAAC;AAC5C,QAAA,wBAAwB,GAAG,KAAK,CAAC;AAEjC,QAAA,kCAAkC,GAAG,EAAE,CAAC;AAExC,QAAA,8BAA8B,GAAG,GAAG,CAAC;AAErC,QAAA,qCAAqC,GAAG,GAAG,CAAC;AAE5C,QAAA,oCAAoC,GAAG,EAAE,CAAC;AAE1C,QAAA,+BAA+B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAK,CAAC;AACvD,QAAA,8BAA8B,GAAG,uCAA+B,GAAG,sCAA8B,CAAC;AAIlG,QAAA,iCAAiC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAK,CAAC;AAGzD,QAAA,uCAAuC,GAAG,GAAG,CAAC;AAE9C,QAAA,sCAAsC,GAAG,IAAK,GAAG,sCAA8B,CAAC;AAEhF,QAAA,6BAA6B,GAAG,IAAA,sBAAS,EAAC,IAAI,CAAC,CAAC;AAGhD,QAAA,4BAA4B,GAAG,IAAA,sBAAS,EAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.shuffleRollercoasterRng = exports.RollercoasterPriceCalculator = void 0;
|
|
4
|
-
var rollercoaster_price_calculator_1 = require("./rollercoaster-price-calculator");
|
|
5
|
-
Object.defineProperty(exports, "RollercoasterPriceCalculator", { enumerable: true, get: function () { return rollercoaster_price_calculator_1.RollercoasterPriceCalculator; } });
|
|
6
|
-
var shuffle_rollercoaster_rng_1 = require("./shuffle-rollercoaster-rng");
|
|
7
|
-
Object.defineProperty(exports, "shuffleRollercoasterRng", { enumerable: true, get: function () { return shuffle_rollercoaster_rng_1.shuffleRollercoasterRng; } });
|
|
8
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/games/rollercoaster/rng/index.ts"],"names":[],"mappings":";;;AAAA,mFAK0C;AAJxC,8IAAA,4BAA4B,OAAA;AAK9B,yEAAsE;AAA7D,oIAAA,uBAAuB,OAAA"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import BigNumber from 'bignumber.js';
|
|
2
|
-
export type RollercoasterRngCheckpoint = {
|
|
3
|
-
tick: number;
|
|
4
|
-
price: BigNumber;
|
|
5
|
-
digest: string;
|
|
6
|
-
};
|
|
7
|
-
export type RollercoasterRandomState = {
|
|
8
|
-
tick: number;
|
|
9
|
-
randomNumber: BigNumber;
|
|
10
|
-
digest: string;
|
|
11
|
-
};
|
|
12
|
-
export type RollercoasterRngFn = (startTickIndex: number, endTickIndex: number, checkpoint?: RollercoasterRngCheckpoint) => RollercoasterRandomState[];
|
|
13
|
-
export declare class RollercoasterPriceCalculator {
|
|
14
|
-
private readonly getRngInRange;
|
|
15
|
-
constructor(getRngInRange: RollercoasterRngFn);
|
|
16
|
-
getPriceAtTick(tickIndex: number, checkpoint?: RollercoasterRngCheckpoint): BigNumber;
|
|
17
|
-
getPricesInTickRange(startTickIndex: number, endTickIndex: number, checkpoint?: RollercoasterRngCheckpoint): RollercoasterRngCheckpoint[];
|
|
18
|
-
private calculateNextPrice;
|
|
19
|
-
private validateRandomNumber;
|
|
20
|
-
private validateRange;
|
|
21
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rollercoaster-price-calculator.js","sourceRoot":"","sources":["../../../../src/games/rollercoaster/rng/rollercoaster-price-calculator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shuffle-rollercoaster-rng.js","sourceRoot":"","sources":["../../../../src/games/rollercoaster/rng/shuffle-rollercoaster-rng.ts"],"names":[],"mappings":";;;;;;AAAA,mCAAoC;AACpC,gEAAqC;AAGrC,SAAgB,uBAAuB,CAAC,UAAkB,EAAE,gBAAwB;IAClF,SAAS,aAAa;QACpB,OAAO,IAAA,mBAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC;IAC5E,CAAC;IAED,SAAS,UAAU,CAAC,MAAc;QAChC,OAAO,IAAA,mBAAU,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC;IACxE,CAAC;IAED,SAAS,oBAAoB,CAAC,UAAsC;QAClE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACrD,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,CAAC,cAAsB,EAAE,YAAoB,EAAE,UAAuC,EAA8B,EAAE;QAC3H,IAAI,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAC7E,MAAM,MAAM,GAA+B,EAAE,CAAC;QAE9C,KAAK,IAAI,IAAI,GAAG,cAAc,EAAE,IAAI,IAAI,YAAY,EAAE,IAAI,EAAE,EAAE,CAAC;YAC7D,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,YAAY,EAAE,IAAA,sBAAS,EAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBAC/C,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;aAC/B,CAAC,CAAC;YACH,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AAhCD,0DAgCC"}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.RollercoasterRules = exports.RollercoasterBetTerminalReason = exports.RollercoasterDirection = void 0;
|
|
7
|
-
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
8
|
-
const calculate_payout_1 = require("../../utils/calculate-payout");
|
|
9
|
-
const constants_1 = require("./constants");
|
|
10
|
-
var RollercoasterDirection;
|
|
11
|
-
(function (RollercoasterDirection) {
|
|
12
|
-
RollercoasterDirection["UP"] = "UP";
|
|
13
|
-
RollercoasterDirection["DOWN"] = "DOWN";
|
|
14
|
-
})(RollercoasterDirection || (exports.RollercoasterDirection = RollercoasterDirection = {}));
|
|
15
|
-
var RollercoasterBetTerminalReason;
|
|
16
|
-
(function (RollercoasterBetTerminalReason) {
|
|
17
|
-
RollercoasterBetTerminalReason["CASHOUT"] = "CASHOUT";
|
|
18
|
-
RollercoasterBetTerminalReason["TAKE_PROFIT"] = "TAKE_PROFIT";
|
|
19
|
-
RollercoasterBetTerminalReason["LIQUIDATION"] = "LIQUIDATION";
|
|
20
|
-
RollercoasterBetTerminalReason["MAX_PAYOUT"] = "MAX_PAYOUT";
|
|
21
|
-
RollercoasterBetTerminalReason["ROUND_END"] = "ROUND_END";
|
|
22
|
-
})(RollercoasterBetTerminalReason || (exports.RollercoasterBetTerminalReason = RollercoasterBetTerminalReason = {}));
|
|
23
|
-
class RollercoasterRules {
|
|
24
|
-
static bustPrice(entryPrice, leverage, direction) {
|
|
25
|
-
const offset = entryPrice.dividedBy(leverage);
|
|
26
|
-
return direction === RollercoasterDirection.UP ? entryPrice.minus(offset) : entryPrice.plus(offset);
|
|
27
|
-
}
|
|
28
|
-
static position(amount, leverage, direction) {
|
|
29
|
-
const magnitude = amount.multipliedBy(leverage);
|
|
30
|
-
return direction === RollercoasterDirection.UP ? magnitude : magnitude.negated();
|
|
31
|
-
}
|
|
32
|
-
static impliedPriceForMultiplier(bet, targetMultiplier) {
|
|
33
|
-
const directionSign = bet.direction === RollercoasterDirection.UP ? 1 : -1;
|
|
34
|
-
const multiplierDelta = targetMultiplier.minus(1);
|
|
35
|
-
const priceChange = (0, bignumber_js_1.default)(directionSign).multipliedBy(multiplierDelta).dividedBy(bet.leverage);
|
|
36
|
-
return bet.entryPrice.multipliedBy((0, bignumber_js_1.default)(1).plus(priceChange));
|
|
37
|
-
}
|
|
38
|
-
static isValidTakeProfitMultiplier(takeProfitMultiplier) {
|
|
39
|
-
return takeProfitMultiplier.isGreaterThan(constants_1.ROLLERCOASTER_MIN_TAKE_PROFIT_MULTIPLIER);
|
|
40
|
-
}
|
|
41
|
-
static isTakeProfitFarEnoughFromEntry(entryPrice, takeProfitImpliedPrice) {
|
|
42
|
-
return takeProfitImpliedPrice.minus(entryPrice).abs().dividedBy(entryPrice).isGreaterThanOrEqualTo(constants_1.ROLLERCOASTER_TP_MIN_PROXIMITY_TO_ENTRY);
|
|
43
|
-
}
|
|
44
|
-
static isTakeProfitFarEnoughFromBust(entryPrice, bustPrice, takeProfitImpliedPrice) {
|
|
45
|
-
return takeProfitImpliedPrice.minus(bustPrice).abs().dividedBy(entryPrice).isGreaterThanOrEqualTo(constants_1.ROLLERCOASTER_TP_MIN_PROXIMITY_TO_BUST);
|
|
46
|
-
}
|
|
47
|
-
static isBustPriceDistinctFromEntry(entryPrice, bustPrice) {
|
|
48
|
-
return !entryPrice
|
|
49
|
-
.decimalPlaces(constants_1.ROLLERCOASTER_INTERNAL_PRICE_DECIMAL_PLACES)
|
|
50
|
-
.isEqualTo(bustPrice.decimalPlaces(constants_1.ROLLERCOASTER_INTERNAL_PRICE_DECIMAL_PLACES));
|
|
51
|
-
}
|
|
52
|
-
static isFinalTick(activeTick) {
|
|
53
|
-
return activeTick >= constants_1.ROLLERCOASTER_ROUND_TICK_COUNT - 1;
|
|
54
|
-
}
|
|
55
|
-
static isClientTickWithinMaxLag(activeTick, lastSeenTick) {
|
|
56
|
-
return activeTick - lastSeenTick <= constants_1.ROLLERCOASTER_MAX_STALE_CLIENT_TICKS;
|
|
57
|
-
}
|
|
58
|
-
static getScheduledRoundId(now, epochMs) {
|
|
59
|
-
return Math.floor((now.getTime() - epochMs) / constants_1.ROLLERCOASTER_ROUND_DURATION_MS);
|
|
60
|
-
}
|
|
61
|
-
static getScheduledRoundStartTime(roundId, epochMs) {
|
|
62
|
-
return new Date(epochMs + roundId * constants_1.ROLLERCOASTER_ROUND_DURATION_MS);
|
|
63
|
-
}
|
|
64
|
-
static tickAtOrAfter(startedAtMs, atMs) {
|
|
65
|
-
return Math.ceil((atMs - startedAtMs) / constants_1.ROLLERCOASTER_TICK_DURATION_MS);
|
|
66
|
-
}
|
|
67
|
-
static tickBefore(startedAtMs, atMs) {
|
|
68
|
-
return RollercoasterRules.tickAtOrAfter(startedAtMs, atMs) - 1;
|
|
69
|
-
}
|
|
70
|
-
static tickStartTime(startedAtMs, tick) {
|
|
71
|
-
return new Date(startedAtMs + tick * constants_1.ROLLERCOASTER_TICK_DURATION_MS);
|
|
72
|
-
}
|
|
73
|
-
static hasReachedTargetPrice(direction, currentPrice, targetPrice) {
|
|
74
|
-
return direction === RollercoasterDirection.UP ? currentPrice.isGreaterThanOrEqualTo(targetPrice) : currentPrice.isLessThanOrEqualTo(targetPrice);
|
|
75
|
-
}
|
|
76
|
-
static hasReachedBust(direction, price, bustPrice) {
|
|
77
|
-
return direction === RollercoasterDirection.UP ? price.isLessThanOrEqualTo(bustPrice) : price.isGreaterThanOrEqualTo(bustPrice);
|
|
78
|
-
}
|
|
79
|
-
static evaluateTriggers(bet, tickPrice, liveMaxPayoutCap) {
|
|
80
|
-
const hitBust = RollercoasterRules.hasReachedBust(bet.direction, tickPrice, bet.bustPrice);
|
|
81
|
-
if (bet.takeProfitMultiplier != null) {
|
|
82
|
-
const takeProfitMultiplier = bet.takeProfitMultiplier;
|
|
83
|
-
const hitTakeProfit = RollercoasterRules.hasReachedTargetPrice(bet.direction, tickPrice, RollercoasterRules.impliedPriceForMultiplier(bet, takeProfitMultiplier));
|
|
84
|
-
if (hitTakeProfit && hitBust) {
|
|
85
|
-
throw new Error('RollercoasterRules.evaluateTriggers: take profit and liquidation both fired');
|
|
86
|
-
}
|
|
87
|
-
if (hitTakeProfit) {
|
|
88
|
-
const reason = { kind: RollercoasterBetTerminalReason.TAKE_PROFIT, takeProfitMultiplier };
|
|
89
|
-
if (RollercoasterRules.grossPayoutForReason(bet, reason, tickPrice).isGreaterThan(liveMaxPayoutCap)) {
|
|
90
|
-
return { fired: true, reason: { kind: RollercoasterBetTerminalReason.MAX_PAYOUT, appliedCap: liveMaxPayoutCap } };
|
|
91
|
-
}
|
|
92
|
-
return { fired: true, reason };
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (hitBust) {
|
|
96
|
-
return { fired: true, reason: { kind: RollercoasterBetTerminalReason.LIQUIDATION } };
|
|
97
|
-
}
|
|
98
|
-
if (RollercoasterRules.grossPayoutAtPrice(bet, tickPrice).isGreaterThanOrEqualTo(liveMaxPayoutCap)) {
|
|
99
|
-
return { fired: true, reason: { kind: RollercoasterBetTerminalReason.MAX_PAYOUT, appliedCap: liveMaxPayoutCap } };
|
|
100
|
-
}
|
|
101
|
-
return { fired: false };
|
|
102
|
-
}
|
|
103
|
-
static multiplierAtPrice(bet, price) {
|
|
104
|
-
const directionSign = bet.direction === RollercoasterDirection.UP ? 1 : -1;
|
|
105
|
-
const percentagePriceChange = price.minus(bet.entryPrice).dividedBy(bet.entryPrice);
|
|
106
|
-
const leveragedPriceChange = (0, bignumber_js_1.default)(directionSign).multipliedBy(bet.leverage).multipliedBy(percentagePriceChange);
|
|
107
|
-
const multiplier = (0, bignumber_js_1.default)(1).plus(leveragedPriceChange);
|
|
108
|
-
return bignumber_js_1.default.maximum(0, multiplier);
|
|
109
|
-
}
|
|
110
|
-
static grossPayoutAtPrice(bet, price) {
|
|
111
|
-
const position = RollercoasterRules.position(bet.amount, bet.leverage, bet.direction);
|
|
112
|
-
const pnl = position.multipliedBy(price.minus(bet.entryPrice)).dividedBy(bet.entryPrice);
|
|
113
|
-
return bignumber_js_1.default.maximum(0, bet.amount.plus(pnl));
|
|
114
|
-
}
|
|
115
|
-
static grossPayoutForReason(bet, reason, price) {
|
|
116
|
-
switch (reason.kind) {
|
|
117
|
-
case RollercoasterBetTerminalReason.TAKE_PROFIT:
|
|
118
|
-
return (0, calculate_payout_1.calculatePayoutBN)(bet.amount, reason.takeProfitMultiplier);
|
|
119
|
-
case RollercoasterBetTerminalReason.LIQUIDATION:
|
|
120
|
-
return (0, bignumber_js_1.default)(0);
|
|
121
|
-
case RollercoasterBetTerminalReason.MAX_PAYOUT:
|
|
122
|
-
return reason.appliedCap;
|
|
123
|
-
case RollercoasterBetTerminalReason.CASHOUT:
|
|
124
|
-
case RollercoasterBetTerminalReason.ROUND_END:
|
|
125
|
-
return RollercoasterRules.grossPayoutAtPrice(bet, price);
|
|
126
|
-
default:
|
|
127
|
-
reason;
|
|
128
|
-
throw new Error(`RollercoasterRules.grossPayoutForReason: unhandled reason`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
static multiplierForReason(bet, reason, price) {
|
|
132
|
-
if (reason.kind === RollercoasterBetTerminalReason.TAKE_PROFIT) {
|
|
133
|
-
return reason.takeProfitMultiplier;
|
|
134
|
-
}
|
|
135
|
-
return RollercoasterRules.multiplierAtPrice(bet, price);
|
|
136
|
-
}
|
|
137
|
-
static netPayout(grossPayout, amount) {
|
|
138
|
-
if (grossPayout.lte(amount)) {
|
|
139
|
-
return grossPayout;
|
|
140
|
-
}
|
|
141
|
-
const profit = grossPayout.minus(amount);
|
|
142
|
-
return amount.plus(profit.multipliedBy((0, bignumber_js_1.default)(1).minus(constants_1.ROLLERCOASTER_PROFIT_FEE_RATE)));
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
exports.RollercoasterRules = RollercoasterRules;
|
|
146
|
-
//# sourceMappingURL=rollercoaster-rules.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rollercoaster-rules.js","sourceRoot":"","sources":["../../../src/games/rollercoaster/rollercoaster-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import BigNumber from 'bignumber.js';
|
|
2
|
-
|
|
3
|
-
export const ROLLERCOASTER_MIN_TAKE_PROFIT_MULTIPLIER = BigNumber(1.05);
|
|
4
|
-
|
|
5
|
-
export const ROLLERCOASTER_TP_MIN_PROXIMITY_TO_ENTRY = BigNumber(0.001);
|
|
6
|
-
export const ROLLERCOASTER_TP_MIN_PROXIMITY_TO_BUST = BigNumber(0.001);
|
|
7
|
-
|
|
8
|
-
// Extra decimal precision carried internally, used only to detect bust price colliding with
|
|
9
|
-
// entry price at high leverage / low price.
|
|
10
|
-
export const ROLLERCOASTER_INTERNAL_PRICE_DECIMAL_PLACES = 10;
|
|
11
|
-
|
|
12
|
-
// configurable platform setting instead of a code constant.
|
|
13
|
-
export const ROLLERCOASTER_MIN_LEVERAGE = BigNumber(1);
|
|
14
|
-
export const ROLLERCOASTER_MAX_LEVERAGE = BigNumber(1000);
|
|
15
|
-
|
|
16
|
-
export const ROLLERCOASTER_MAX_ACTIVE_BETS_PER_ACCOUNT = 20;
|
|
17
|
-
|
|
18
|
-
export const ROLLERCOASTER_START_PRICE = BigNumber(1000);
|
|
19
|
-
export const ROLLERCOASTER_VOLATILITY = 0.001;
|
|
20
|
-
|
|
21
|
-
export const ROLLERCOASTER_PRICE_DECIMAL_PLACES = 10;
|
|
22
|
-
|
|
23
|
-
export const ROLLERCOASTER_TICK_DURATION_MS = 500;
|
|
24
|
-
|
|
25
|
-
export const ROLLERCOASTER_SET_TICK_RETRY_DELAY_MS = 400;
|
|
26
|
-
|
|
27
|
-
export const ROLLERCOASTER_MAX_STALE_CLIENT_TICKS = 10;
|
|
28
|
-
|
|
29
|
-
export const ROLLERCOASTER_ROUND_DURATION_MS = 24 * 60 * 60 * 1_000;
|
|
30
|
-
export const ROLLERCOASTER_ROUND_TICK_COUNT = ROLLERCOASTER_ROUND_DURATION_MS / ROLLERCOASTER_TICK_DURATION_MS;
|
|
31
|
-
|
|
32
|
-
// How far back rollercoasterRecentTicks will page into history before forcing the client onto
|
|
33
|
-
// rollercoasterOhlcHistory instead. PM-approved cap, not derived from any technical constraint.
|
|
34
|
-
export const ROLLERCOASTER_MAX_TICK_HISTORY_MS = 48 * 60 * 60 * 1_000;
|
|
35
|
-
|
|
36
|
-
// price is stored in cache every 500 ticks
|
|
37
|
-
export const ROLLERCOASTER_CHECKPOINT_INTERVAL_TICKS = 500;
|
|
38
|
-
|
|
39
|
-
export const ROLLERCOASTER_PRICE_BAR_INTERVAL_TICKS = 5_000 / ROLLERCOASTER_TICK_DURATION_MS;
|
|
40
|
-
|
|
41
|
-
export const ROLLERCOASTER_PROFIT_FEE_RATE = BigNumber(0.05);
|
|
42
|
-
|
|
43
|
-
// Keep well under 2^53: contracts cross into Redis Lua's tonumber(), which loses precision above that (unlike BigNumber here)
|
|
44
|
-
export const ROLLERCOASTER_CONTRACT_SCALE = BigNumber(10).pow(6);
|