@riocrypto/common-server 1.0.2777 → 1.0.2780
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/build/helpers/find-user-tier-forward-curve-rate.d.ts +17 -0
- package/build/helpers/find-user-tier-forward-curve-rate.js +42 -0
- package/build/helpers/get-resolved-forward-curve-tiers.d.ts +35 -0
- package/build/helpers/get-resolved-forward-curve-tiers.js +78 -0
- package/build/helpers/interpolate-forward-curve-rate.d.ts +15 -0
- package/build/helpers/interpolate-forward-curve-rate.js +49 -0
- package/build/helpers/resolve-forward-curve-rate.d.ts +19 -0
- package/build/helpers/resolve-forward-curve-rate.js +39 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +4 -0
- package/package.json +2 -2
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Country, Side, User } from "@riocrypto/common";
|
|
2
|
+
/**
|
|
3
|
+
* Walks the user's tier ranges from the current tier (matched by amount)
|
|
4
|
+
* down to lower tiers, returning the first defined interpolated rate.
|
|
5
|
+
*
|
|
6
|
+
* Mirrors the tier-walk used in fee resolution so a higher tier whose
|
|
7
|
+
* forward curve omits a day can still inherit from a lower tier with a more
|
|
8
|
+
* complete curve. Returns undefined if no tier matches the amount or no
|
|
9
|
+
* tier contains the requested day.
|
|
10
|
+
*/
|
|
11
|
+
export declare const findUserTierForwardCurveRate: ({ user, country, side, amount, day, }: {
|
|
12
|
+
user: User | undefined | null;
|
|
13
|
+
country: Country;
|
|
14
|
+
side: Side;
|
|
15
|
+
amount: number;
|
|
16
|
+
day: number;
|
|
17
|
+
}) => number | undefined;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findUserTierForwardCurveRate = void 0;
|
|
4
|
+
const interpolate_forward_curve_rate_1 = require("./interpolate-forward-curve-rate");
|
|
5
|
+
/**
|
|
6
|
+
* Walks the user's tier ranges from the current tier (matched by amount)
|
|
7
|
+
* down to lower tiers, returning the first defined interpolated rate.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the tier-walk used in fee resolution so a higher tier whose
|
|
10
|
+
* forward curve omits a day can still inherit from a lower tier with a more
|
|
11
|
+
* complete curve. Returns undefined if no tier matches the amount or no
|
|
12
|
+
* tier contains the requested day.
|
|
13
|
+
*/
|
|
14
|
+
const findUserTierForwardCurveRate = ({ user, country, side, amount, day, }) => {
|
|
15
|
+
var _a, _b;
|
|
16
|
+
const ranges = (_b = (_a = user === null || user === void 0 ? void 0 : user.platformFeeRanges) === null || _a === void 0 ? void 0 : _a[country]) === null || _b === void 0 ? void 0 : _b[side];
|
|
17
|
+
if (!ranges || ranges.length === 0)
|
|
18
|
+
return undefined;
|
|
19
|
+
const sorted = [...ranges].sort((a, b) => a.min - b.min);
|
|
20
|
+
let currentRangeIndex = -1;
|
|
21
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
22
|
+
const range = sorted[i];
|
|
23
|
+
if (range.min <= amount && range.max >= amount) {
|
|
24
|
+
currentRangeIndex = i;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (currentRangeIndex === -1 &&
|
|
29
|
+
sorted.length > 0 &&
|
|
30
|
+
amount > sorted[sorted.length - 1].max) {
|
|
31
|
+
currentRangeIndex = sorted.length - 1;
|
|
32
|
+
}
|
|
33
|
+
if (currentRangeIndex === -1)
|
|
34
|
+
return undefined;
|
|
35
|
+
for (let i = currentRangeIndex; i >= 0; i--) {
|
|
36
|
+
const rate = (0, interpolate_forward_curve_rate_1.interpolateForwardCurveRate)(sorted[i].twoWaySettlementDateOffsetFee, day);
|
|
37
|
+
if (rate !== undefined)
|
|
38
|
+
return rate;
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
};
|
|
42
|
+
exports.findUserTierForwardCurveRate = findUserTierForwardCurveRate;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Country, RioSettings, Side, User } from "@riocrypto/common";
|
|
2
|
+
export type ResolvedForwardCurveTier = {
|
|
3
|
+
min: number;
|
|
4
|
+
max: number;
|
|
5
|
+
/**
|
|
6
|
+
* Anchor points keyed by day (string for transport / MongoDB
|
|
7
|
+
* compatibility) -> rate (decimal, e.g. 0.0005 = 5 BPS).
|
|
8
|
+
*
|
|
9
|
+
* The set of keys is the union of every day defined by any layer relevant
|
|
10
|
+
* to this tier (user tier, lower user tiers, broker tiers, platform
|
|
11
|
+
* default). At each key the resolved value is what the trader would
|
|
12
|
+
* actually be charged at that T+n, so visual interpolation between anchor
|
|
13
|
+
* points produces a single continuous curve covering the full range.
|
|
14
|
+
*/
|
|
15
|
+
curve: {
|
|
16
|
+
[day: string]: number;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Builds per-tier resolved forward curves suitable for charting.
|
|
21
|
+
*
|
|
22
|
+
* Tiers come from the user's amount tiers when defined, otherwise from the
|
|
23
|
+
* broker's tiers, otherwise a single synthetic tier covering the platform
|
|
24
|
+
* default. For each tier, every "anchor day" defined anywhere in the
|
|
25
|
+
* fallback chain is filled with the resolved rate at that day; the chart
|
|
26
|
+
* can then linearly interpolate between anchors to render a single
|
|
27
|
+
* continuous line.
|
|
28
|
+
*/
|
|
29
|
+
export declare const getResolvedForwardCurveTiers: ({ user, broker, country, side, rioSettings, }: {
|
|
30
|
+
user: User;
|
|
31
|
+
broker?: User | null | undefined;
|
|
32
|
+
country: Country;
|
|
33
|
+
side: Side;
|
|
34
|
+
rioSettings: Pick<RioSettings, "defaultTwoWaySettlementDateOffsetFee">;
|
|
35
|
+
}) => ResolvedForwardCurveTier[];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getResolvedForwardCurveTiers = void 0;
|
|
4
|
+
const resolve_forward_curve_rate_1 = require("./resolve-forward-curve-rate");
|
|
5
|
+
/**
|
|
6
|
+
* Builds per-tier resolved forward curves suitable for charting.
|
|
7
|
+
*
|
|
8
|
+
* Tiers come from the user's amount tiers when defined, otherwise from the
|
|
9
|
+
* broker's tiers, otherwise a single synthetic tier covering the platform
|
|
10
|
+
* default. For each tier, every "anchor day" defined anywhere in the
|
|
11
|
+
* fallback chain is filled with the resolved rate at that day; the chart
|
|
12
|
+
* can then linearly interpolate between anchors to render a single
|
|
13
|
+
* continuous line.
|
|
14
|
+
*/
|
|
15
|
+
const getResolvedForwardCurveTiers = ({ user, broker, country, side, rioSettings, }) => {
|
|
16
|
+
var _a, _b, _c, _d, _e, _f;
|
|
17
|
+
const userRanges = (_b = (_a = user.platformFeeRanges) === null || _a === void 0 ? void 0 : _a[country]) === null || _b === void 0 ? void 0 : _b[side];
|
|
18
|
+
const brokerRanges = (_d = (_c = broker === null || broker === void 0 ? void 0 : broker.platformFeeRanges) === null || _c === void 0 ? void 0 : _c[country]) === null || _d === void 0 ? void 0 : _d[side];
|
|
19
|
+
const platformCurve = (_f = (_e = rioSettings.defaultTwoWaySettlementDateOffsetFee) === null || _e === void 0 ? void 0 : _e[country]) === null || _f === void 0 ? void 0 : _f[side];
|
|
20
|
+
let tiers = [];
|
|
21
|
+
if (userRanges && userRanges.length > 0) {
|
|
22
|
+
tiers = [...userRanges]
|
|
23
|
+
.sort((a, b) => a.min - b.min)
|
|
24
|
+
.map((r) => ({ min: r.min, max: r.max }));
|
|
25
|
+
}
|
|
26
|
+
else if (brokerRanges && brokerRanges.length > 0) {
|
|
27
|
+
tiers = [...brokerRanges]
|
|
28
|
+
.sort((a, b) => a.min - b.min)
|
|
29
|
+
.map((r) => ({ min: r.min, max: r.max }));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
tiers = [{ min: 0, max: Number.MAX_SAFE_INTEGER }];
|
|
33
|
+
}
|
|
34
|
+
const collectDays = (curve) => {
|
|
35
|
+
if (!curve)
|
|
36
|
+
return [];
|
|
37
|
+
return Object.keys(curve)
|
|
38
|
+
.map((k) => Number(k))
|
|
39
|
+
.filter((d) => Number.isFinite(d));
|
|
40
|
+
};
|
|
41
|
+
const anchorDays = new Set();
|
|
42
|
+
if (userRanges) {
|
|
43
|
+
for (const r of userRanges) {
|
|
44
|
+
collectDays(r.twoWaySettlementDateOffsetFee).forEach((d) => anchorDays.add(d));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (brokerRanges) {
|
|
48
|
+
for (const r of brokerRanges) {
|
|
49
|
+
collectDays(r.twoWaySettlementDateOffsetFee).forEach((d) => anchorDays.add(d));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
collectDays(platformCurve).forEach((d) => anchorDays.add(d));
|
|
53
|
+
if (anchorDays.size === 0) {
|
|
54
|
+
return tiers.map((t) => (Object.assign(Object.assign({}, t), { curve: {} })));
|
|
55
|
+
}
|
|
56
|
+
const sortedDays = [...anchorDays].sort((a, b) => a - b);
|
|
57
|
+
return tiers.map((tier) => {
|
|
58
|
+
const sampleAmount = tier.max >= Number.MAX_SAFE_INTEGER
|
|
59
|
+
? tier.min + 1
|
|
60
|
+
: Math.floor((tier.min + tier.max) / 2);
|
|
61
|
+
const curve = {};
|
|
62
|
+
for (const day of sortedDays) {
|
|
63
|
+
const rate = (0, resolve_forward_curve_rate_1.resolveForwardCurveRate)({
|
|
64
|
+
user,
|
|
65
|
+
broker,
|
|
66
|
+
country,
|
|
67
|
+
side,
|
|
68
|
+
amount: sampleAmount,
|
|
69
|
+
day,
|
|
70
|
+
rioSettings,
|
|
71
|
+
});
|
|
72
|
+
if (rate !== undefined)
|
|
73
|
+
curve[String(day)] = rate;
|
|
74
|
+
}
|
|
75
|
+
return Object.assign(Object.assign({}, tier), { curve });
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
exports.getResolvedForwardCurveTiers = getResolvedForwardCurveTiers;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type ForwardCurve = {
|
|
2
|
+
[day: number]: number;
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* Linearly interpolates a forward curve at a given day.
|
|
6
|
+
*
|
|
7
|
+
* - Returns the rate at the requested day, with linear interpolation between
|
|
8
|
+
* defined points.
|
|
9
|
+
* - Returns undefined if the requested day is outside [minDefinedDay,
|
|
10
|
+
* maxDefinedDay] or if the curve has no defined points.
|
|
11
|
+
*
|
|
12
|
+
* Days outside the defined range are intentionally undefined so callers can
|
|
13
|
+
* fall back to the next layer (broker parent curve or platform default).
|
|
14
|
+
*/
|
|
15
|
+
export declare const interpolateForwardCurveRate: (curve: ForwardCurve | undefined, daysUntilSettlementDate: number) => number | undefined;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.interpolateForwardCurveRate = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Linearly interpolates a forward curve at a given day.
|
|
6
|
+
*
|
|
7
|
+
* - Returns the rate at the requested day, with linear interpolation between
|
|
8
|
+
* defined points.
|
|
9
|
+
* - Returns undefined if the requested day is outside [minDefinedDay,
|
|
10
|
+
* maxDefinedDay] or if the curve has no defined points.
|
|
11
|
+
*
|
|
12
|
+
* Days outside the defined range are intentionally undefined so callers can
|
|
13
|
+
* fall back to the next layer (broker parent curve or platform default).
|
|
14
|
+
*/
|
|
15
|
+
const interpolateForwardCurveRate = (curve, daysUntilSettlementDate) => {
|
|
16
|
+
if (!curve)
|
|
17
|
+
return undefined;
|
|
18
|
+
const definedDays = Object.keys(curve)
|
|
19
|
+
.map((key) => Number(key))
|
|
20
|
+
.filter((day) => Number.isFinite(day) && curve[day] !== undefined)
|
|
21
|
+
.sort((a, b) => a - b);
|
|
22
|
+
if (definedDays.length === 0)
|
|
23
|
+
return undefined;
|
|
24
|
+
const minDay = definedDays[0];
|
|
25
|
+
const maxDay = definedDays[definedDays.length - 1];
|
|
26
|
+
if (daysUntilSettlementDate < minDay || daysUntilSettlementDate > maxDay) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
if (curve[daysUntilSettlementDate] !== undefined) {
|
|
30
|
+
return curve[daysUntilSettlementDate];
|
|
31
|
+
}
|
|
32
|
+
let lowerDay = definedDays[0];
|
|
33
|
+
let upperDay = definedDays[definedDays.length - 1];
|
|
34
|
+
for (let i = 0; i < definedDays.length - 1; i++) {
|
|
35
|
+
if (definedDays[i] <= daysUntilSettlementDate &&
|
|
36
|
+
definedDays[i + 1] >= daysUntilSettlementDate) {
|
|
37
|
+
lowerDay = definedDays[i];
|
|
38
|
+
upperDay = definedDays[i + 1];
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const lowerFee = curve[lowerDay];
|
|
43
|
+
const upperFee = curve[upperDay];
|
|
44
|
+
if (upperDay === lowerDay)
|
|
45
|
+
return lowerFee;
|
|
46
|
+
const slope = (upperFee - lowerFee) / (upperDay - lowerDay);
|
|
47
|
+
return lowerFee + slope * (daysUntilSettlementDate - lowerDay);
|
|
48
|
+
};
|
|
49
|
+
exports.interpolateForwardCurveRate = interpolateForwardCurveRate;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Country, RioSettings, Side, User } from "@riocrypto/common";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the effective two-way-settlement-date-offset rate at a given day,
|
|
4
|
+
* walking the full fallback chain:
|
|
5
|
+
* 1. user's own tier curves (current tier and lower)
|
|
6
|
+
* 2. broker parent's tier curves (same logic applied to broker)
|
|
7
|
+
* 3. platform default forward curve from RioSettings
|
|
8
|
+
*
|
|
9
|
+
* Returns undefined only if every layer is missing or out of range.
|
|
10
|
+
*/
|
|
11
|
+
export declare const resolveForwardCurveRate: ({ user, broker, country, side, amount, day, rioSettings, }: {
|
|
12
|
+
user: User | undefined | null;
|
|
13
|
+
broker?: User | null | undefined;
|
|
14
|
+
country: Country;
|
|
15
|
+
side: Side;
|
|
16
|
+
amount: number;
|
|
17
|
+
day: number;
|
|
18
|
+
rioSettings: Pick<RioSettings, "defaultTwoWaySettlementDateOffsetFee">;
|
|
19
|
+
}) => number | undefined;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveForwardCurveRate = void 0;
|
|
4
|
+
const find_user_tier_forward_curve_rate_1 = require("./find-user-tier-forward-curve-rate");
|
|
5
|
+
const interpolate_forward_curve_rate_1 = require("./interpolate-forward-curve-rate");
|
|
6
|
+
/**
|
|
7
|
+
* Resolves the effective two-way-settlement-date-offset rate at a given day,
|
|
8
|
+
* walking the full fallback chain:
|
|
9
|
+
* 1. user's own tier curves (current tier and lower)
|
|
10
|
+
* 2. broker parent's tier curves (same logic applied to broker)
|
|
11
|
+
* 3. platform default forward curve from RioSettings
|
|
12
|
+
*
|
|
13
|
+
* Returns undefined only if every layer is missing or out of range.
|
|
14
|
+
*/
|
|
15
|
+
const resolveForwardCurveRate = ({ user, broker, country, side, amount, day, rioSettings, }) => {
|
|
16
|
+
var _a, _b;
|
|
17
|
+
const userRate = (0, find_user_tier_forward_curve_rate_1.findUserTierForwardCurveRate)({
|
|
18
|
+
user,
|
|
19
|
+
country,
|
|
20
|
+
side,
|
|
21
|
+
amount,
|
|
22
|
+
day,
|
|
23
|
+
});
|
|
24
|
+
if (userRate !== undefined)
|
|
25
|
+
return userRate;
|
|
26
|
+
if (broker) {
|
|
27
|
+
const brokerRate = (0, find_user_tier_forward_curve_rate_1.findUserTierForwardCurveRate)({
|
|
28
|
+
user: broker,
|
|
29
|
+
country,
|
|
30
|
+
side,
|
|
31
|
+
amount,
|
|
32
|
+
day,
|
|
33
|
+
});
|
|
34
|
+
if (brokerRate !== undefined)
|
|
35
|
+
return brokerRate;
|
|
36
|
+
}
|
|
37
|
+
return (0, interpolate_forward_curve_rate_1.interpolateForwardCurveRate)((_b = (_a = rioSettings.defaultTwoWaySettlementDateOffsetFee) === null || _a === void 0 ? void 0 : _a[country]) === null || _b === void 0 ? void 0 : _b[side], day);
|
|
38
|
+
};
|
|
39
|
+
exports.resolveForwardCurveRate = resolveForwardCurveRate;
|
package/build/index.d.ts
CHANGED
|
@@ -166,3 +166,7 @@ export * from "./helpers/extract-error-message";
|
|
|
166
166
|
export * from "./helpers/get-exchange-rates-with-markups";
|
|
167
167
|
export * from "./helpers/get-order-from-static-reference";
|
|
168
168
|
export * from "./helpers/is-after-hours";
|
|
169
|
+
export * from "./helpers/interpolate-forward-curve-rate";
|
|
170
|
+
export * from "./helpers/find-user-tier-forward-curve-rate";
|
|
171
|
+
export * from "./helpers/resolve-forward-curve-rate";
|
|
172
|
+
export * from "./helpers/get-resolved-forward-curve-tiers";
|
package/build/index.js
CHANGED
|
@@ -182,3 +182,7 @@ __exportStar(require("./helpers/extract-error-message"), exports);
|
|
|
182
182
|
__exportStar(require("./helpers/get-exchange-rates-with-markups"), exports);
|
|
183
183
|
__exportStar(require("./helpers/get-order-from-static-reference"), exports);
|
|
184
184
|
__exportStar(require("./helpers/is-after-hours"), exports);
|
|
185
|
+
__exportStar(require("./helpers/interpolate-forward-curve-rate"), exports);
|
|
186
|
+
__exportStar(require("./helpers/find-user-tier-forward-curve-rate"), exports);
|
|
187
|
+
__exportStar(require("./helpers/resolve-forward-curve-rate"), exports);
|
|
188
|
+
__exportStar(require("./helpers/get-resolved-forward-curve-tiers"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riocrypto/common-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2780",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@google-cloud/secret-manager": "^5.6.0",
|
|
25
25
|
"@google-cloud/storage": "^7.19.0",
|
|
26
26
|
"@hyperdx/node-opentelemetry": "^0.10.3",
|
|
27
|
-
"@riocrypto/common": "1.0.
|
|
27
|
+
"@riocrypto/common": "1.0.2582",
|
|
28
28
|
"@slack/web-api": "^7.15.0",
|
|
29
29
|
"@types/express": "^4.17.25",
|
|
30
30
|
"axios": "1.13.6",
|