@signals-protocol/v1-sdk 1.0.0 → 1.2.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.
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildDistributionVNode = buildDistributionVNode;
4
+ const h_1 = require("./h");
5
+ const assets_1 = require("./assets");
6
+ const distribution_share_utils_1 = require("./distribution-share-utils");
7
+ const BAR_COLORS = {
8
+ peak: { bg: "#F7931A", opacity: 0.9 },
9
+ high: { bg: "#2d88ff", opacity: 0.5 },
10
+ mid: { bg: "#5a6a7a", opacity: 0.3 },
11
+ low: { bg: "#3a4555", opacity: 0.15 },
12
+ };
13
+ function formatPrice(price) {
14
+ return "$" + Math.round(price).toLocaleString("en-US");
15
+ }
16
+ function buildDistributionVNode(input) {
17
+ const { distribution, minTick, maxTick, tickSpacing, closingPriceDate, currentPrice, } = input;
18
+ const maxProb = Math.max(...distribution.map((d) => d.probability));
19
+ const [peakLo, peakHi] = (0, distribution_share_utils_1.getPeakRange)(distribution, tickSpacing);
20
+ const xTicks = (0, distribution_share_utils_1.generateXAxisTicks)(minTick, maxTick);
21
+ const range = maxTick - minTick;
22
+ // Build histogram bars
23
+ const bars = distribution.map((tick) => {
24
+ const category = (0, distribution_share_utils_1.getBarCategory)(tick.probability, maxProb);
25
+ const height = (0, distribution_share_utils_1.getSqrtHeight)(tick.probability, maxProb);
26
+ const { bg, opacity } = BAR_COLORS[category];
27
+ const isPeak = category === "peak";
28
+ if (isPeak) {
29
+ return (0, h_1.h)("div", {
30
+ style: {
31
+ display: "flex",
32
+ flexDirection: "column",
33
+ flex: 1,
34
+ minWidth: 0,
35
+ height: `${height}%`,
36
+ alignItems: "center",
37
+ justifyContent: "flex-end",
38
+ },
39
+ }, (0, h_1.h)("span", {
40
+ style: {
41
+ fontSize: 14,
42
+ fontWeight: 700,
43
+ color: "#F7931A",
44
+ marginBottom: 4,
45
+ },
46
+ }, `${(tick.probability * 100).toFixed(1)}%`), (0, h_1.h)("div", {
47
+ style: {
48
+ width: "100%",
49
+ flex: 1,
50
+ background: bg,
51
+ opacity,
52
+ borderRadius: "3px 3px 0 0",
53
+ },
54
+ }));
55
+ }
56
+ return (0, h_1.h)("div", {
57
+ style: {
58
+ flex: 1,
59
+ minWidth: 0,
60
+ height: `${height}%`,
61
+ display: "flex",
62
+ },
63
+ }, (0, h_1.h)("div", {
64
+ style: {
65
+ width: "100%",
66
+ height: "100%",
67
+ background: bg,
68
+ opacity,
69
+ borderRadius: "3px 3px 0 0",
70
+ },
71
+ }));
72
+ });
73
+ // X-axis labels
74
+ const xLabels = xTicks.map((price) => {
75
+ const pos = ((price - minTick) / range) * 100;
76
+ return (0, h_1.h)("div", {
77
+ style: {
78
+ position: "absolute",
79
+ left: `${pos}%`,
80
+ fontSize: 15,
81
+ fontWeight: 500,
82
+ color: "rgba(255,255,255,0.5)",
83
+ display: "flex",
84
+ },
85
+ }, (0, distribution_share_utils_1.formatXTick)(price));
86
+ });
87
+ return (0, h_1.h)("div", {
88
+ style: {
89
+ width: 1200,
90
+ height: 630,
91
+ display: "flex",
92
+ flexDirection: "column",
93
+ fontFamily: "Inter",
94
+ background: "linear-gradient(140deg, #0a1120, #0d1730)",
95
+ padding: "40px 48px 28px",
96
+ },
97
+ },
98
+ // Main row
99
+ (0, h_1.h)("div", {
100
+ style: { display: "flex", flex: 1, gap: 40, minHeight: 0 },
101
+ },
102
+ // Left panel
103
+ (0, h_1.h)("div", {
104
+ style: {
105
+ display: "flex",
106
+ flexDirection: "column",
107
+ width: 340,
108
+ flexShrink: 0,
109
+ },
110
+ },
111
+ // Logo
112
+ (0, h_1.h)("div", {
113
+ style: {
114
+ display: "flex",
115
+ alignItems: "center",
116
+ gap: 12,
117
+ marginBottom: 28,
118
+ },
119
+ }, (0, h_1.h)("img", {
120
+ src: assets_1.SIGNALS_LOGO_URI,
121
+ width: 34,
122
+ height: 32,
123
+ style: { display: "flex" },
124
+ }), (0, h_1.h)("span", {
125
+ style: { fontSize: 30, fontWeight: 700, color: "#1444c2" },
126
+ }, "Signals")),
127
+ // Market question
128
+ (0, h_1.h)("div", {
129
+ style: {
130
+ fontSize: 28,
131
+ color: "#fff",
132
+ lineHeight: 1.3,
133
+ marginBottom: 16,
134
+ fontWeight: 700,
135
+ display: "flex",
136
+ },
137
+ }, `BTC Price on ${closingPriceDate}?`),
138
+ // Stats
139
+ (0, h_1.h)("div", {
140
+ style: {
141
+ display: "flex",
142
+ flexDirection: "column",
143
+ gap: 20,
144
+ marginTop: 20,
145
+ },
146
+ },
147
+ // Most Likely Price
148
+ (0, h_1.h)("div", {
149
+ style: {
150
+ display: "flex",
151
+ flexDirection: "column",
152
+ },
153
+ }, (0, h_1.h)("div", {
154
+ style: {
155
+ fontSize: 14,
156
+ letterSpacing: "0.05em",
157
+ textTransform: "uppercase",
158
+ color: "rgba(255,255,255,0.5)",
159
+ marginBottom: 4,
160
+ display: "flex",
161
+ },
162
+ }, "Most Likely Price"), (0, h_1.h)("div", {
163
+ style: {
164
+ fontSize: 40,
165
+ lineHeight: 1.1,
166
+ color: "#F7931A",
167
+ fontWeight: 700,
168
+ display: "flex",
169
+ },
170
+ }, (0, distribution_share_utils_1.formatDistributionPriceRange)(peakLo, peakHi))),
171
+ // Current Price
172
+ ...(currentPrice != null
173
+ ? [
174
+ (0, h_1.h)("div", {
175
+ style: {
176
+ display: "flex",
177
+ flexDirection: "column",
178
+ },
179
+ }, (0, h_1.h)("div", {
180
+ style: {
181
+ fontSize: 14,
182
+ letterSpacing: "0.05em",
183
+ textTransform: "uppercase",
184
+ color: "rgba(255,255,255,0.5)",
185
+ marginBottom: 4,
186
+ display: "flex",
187
+ },
188
+ }, "Current Price"), (0, h_1.h)("div", {
189
+ style: {
190
+ fontSize: 28,
191
+ lineHeight: 1.1,
192
+ color: "#fff",
193
+ fontWeight: 700,
194
+ display: "flex",
195
+ },
196
+ }, formatPrice(currentPrice))),
197
+ ]
198
+ : [])),
199
+ // Spacer
200
+ (0, h_1.h)("div", { style: { flex: 1, display: "flex" } })),
201
+ // Right panel — histogram
202
+ (0, h_1.h)("div", {
203
+ style: {
204
+ flex: 1,
205
+ display: "flex",
206
+ flexDirection: "column",
207
+ },
208
+ },
209
+ // Chart subtitle
210
+ (0, h_1.h)("div", {
211
+ style: {
212
+ textAlign: "right",
213
+ fontSize: 14,
214
+ color: "rgba(255,255,255,0.5)",
215
+ marginBottom: 6,
216
+ flexShrink: 0,
217
+ display: "flex",
218
+ justifyContent: "flex-end",
219
+ },
220
+ }, `$${tickSpacing} ranges`),
221
+ // Histogram area
222
+ (0, h_1.h)("div", {
223
+ style: {
224
+ flex: 1,
225
+ display: "flex",
226
+ flexDirection: "column",
227
+ position: "relative",
228
+ },
229
+ },
230
+ // Bars
231
+ (0, h_1.h)("div", {
232
+ style: {
233
+ flex: 1,
234
+ display: "flex",
235
+ alignItems: "flex-end",
236
+ gap: 1,
237
+ paddingTop: 22,
238
+ },
239
+ }, ...bars),
240
+ // Current price vertical marker
241
+ ...(currentPrice != null &&
242
+ currentPrice >= minTick &&
243
+ currentPrice <= maxTick
244
+ ? [
245
+ (0, h_1.h)("div", {
246
+ style: {
247
+ position: "absolute",
248
+ left: `${((currentPrice - minTick) / range) * 100}%`,
249
+ top: 0,
250
+ bottom: 28,
251
+ width: 2,
252
+ background: "rgba(255,255,255,0.6)",
253
+ display: "flex",
254
+ },
255
+ }),
256
+ (0, h_1.h)("div", {
257
+ style: {
258
+ position: "absolute",
259
+ left: `${((currentPrice - minTick) / range) * 100}%`,
260
+ top: 2,
261
+ fontSize: 11,
262
+ fontWeight: 700,
263
+ color: "rgba(255,255,255,0.7)",
264
+ display: "flex",
265
+ marginLeft: 6,
266
+ },
267
+ }, "Current"),
268
+ ]
269
+ : []),
270
+ // X-axis
271
+ (0, h_1.h)("div", {
272
+ style: {
273
+ display: "flex",
274
+ position: "relative",
275
+ borderTop: "1px solid rgba(255,255,255,0.1)",
276
+ height: 28,
277
+ paddingTop: 8,
278
+ },
279
+ }, ...xLabels)))),
280
+ // Footer
281
+ (0, h_1.h)("div", {
282
+ style: {
283
+ display: "flex",
284
+ justifyContent: "space-between",
285
+ alignItems: "center",
286
+ paddingTop: 10,
287
+ flexShrink: 0,
288
+ },
289
+ }, (0, h_1.h)("span", {
290
+ style: { fontSize: 14, color: "rgba(255,255,255,0.5)" },
291
+ }, "@signalswtf"), (0, h_1.h)("span", {
292
+ style: { fontSize: 14, color: "rgba(255,255,255,0.5)" },
293
+ }, "signals.wtf")));
294
+ }
@@ -0,0 +1,8 @@
1
+ import type { BarCategory, PriceTick } from "./types";
2
+ export declare function getBarCategory(prob: number, maxProb: number): BarCategory;
3
+ export declare function getSqrtHeight(prob: number, maxProb: number): number;
4
+ export declare function generateXAxisTicks(minTick: number, maxTick: number, targetCount?: number): number[];
5
+ export declare function formatXTick(price: number): string;
6
+ export declare function getPeakRange(distribution: PriceTick[], tickSpacing: number): [number, number];
7
+ /** Distribution-specific price range format (em-dash, no decimals) */
8
+ export declare function formatDistributionPriceRange(lo: number, hi: number): string;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBarCategory = getBarCategory;
4
+ exports.getSqrtHeight = getSqrtHeight;
5
+ exports.generateXAxisTicks = generateXAxisTicks;
6
+ exports.formatXTick = formatXTick;
7
+ exports.getPeakRange = getPeakRange;
8
+ exports.formatDistributionPriceRange = formatDistributionPriceRange;
9
+ function getBarCategory(prob, maxProb) {
10
+ if (prob === maxProb)
11
+ return "peak";
12
+ if (prob > maxProb * 0.4)
13
+ return "high";
14
+ if (prob > 0.001)
15
+ return "mid";
16
+ return "low";
17
+ }
18
+ function getSqrtHeight(prob, maxProb) {
19
+ if (prob <= 0.001)
20
+ return 0.8;
21
+ return Math.max(Math.sqrt(prob / maxProb) * 100, 1.5);
22
+ }
23
+ const TICK_STEPS = [500, 1000, 2000, 5000, 10000, 20000];
24
+ function generateXAxisTicks(minTick, maxTick, targetCount = 6) {
25
+ const range = maxTick - minTick;
26
+ let bestStep = 2000;
27
+ let bestDiff = Infinity;
28
+ for (const step of TICK_STEPS) {
29
+ const count = Math.floor(range / step);
30
+ const diff = Math.abs(count - targetCount);
31
+ if (diff < bestDiff) {
32
+ bestDiff = diff;
33
+ bestStep = step;
34
+ }
35
+ }
36
+ const ticks = [];
37
+ const firstTick = Math.ceil(minTick / bestStep) * bestStep;
38
+ for (let t = firstTick; t <= maxTick; t += bestStep) {
39
+ ticks.push(t);
40
+ }
41
+ return ticks;
42
+ }
43
+ function formatXTick(price) {
44
+ return `$${Math.round(price / 1000)}K`;
45
+ }
46
+ function getPeakRange(distribution, tickSpacing) {
47
+ let peakIdx = 0;
48
+ let maxProb = -1;
49
+ for (let i = 0; i < distribution.length; i++) {
50
+ if (distribution[i].probability > maxProb) {
51
+ maxProb = distribution[i].probability;
52
+ peakIdx = i;
53
+ }
54
+ }
55
+ const halfSpacing = tickSpacing / 2;
56
+ const peakPrice = distribution[peakIdx].price;
57
+ return [peakPrice - halfSpacing, peakPrice + halfSpacing];
58
+ }
59
+ /** Distribution-specific price range format (em-dash, no decimals) */
60
+ function formatDistributionPriceRange(lo, hi) {
61
+ const fmt = (v) => "$" + v.toLocaleString("en-US");
62
+ return `${fmt(lo)}\u2013${fmt(hi)}`;
63
+ }
@@ -0,0 +1,6 @@
1
+ export declare function formatUSDC(raw: string): string;
2
+ export declare function formatPrice(tick: number): string;
3
+ export declare function formatPriceRange(lower: number, upper: number): string;
4
+ export declare function percForm(value: number): string;
5
+ export declare function formatUsdPnl(value: number): string;
6
+ export declare function getPnlColor(pnl: number, neutral: string): string;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatUSDC = formatUSDC;
4
+ exports.formatPrice = formatPrice;
5
+ exports.formatPriceRange = formatPriceRange;
6
+ exports.percForm = percForm;
7
+ exports.formatUsdPnl = formatUsdPnl;
8
+ exports.getPnlColor = getPnlColor;
9
+ const USDC_DECIMALS = 6;
10
+ function formatUSDC(raw) {
11
+ const num = Number(raw) / 10 ** USDC_DECIMALS;
12
+ if (num >= 1000)
13
+ return ("$" +
14
+ num.toLocaleString("en-US", {
15
+ minimumFractionDigits: 0,
16
+ maximumFractionDigits: 0,
17
+ }));
18
+ return ("$" +
19
+ num.toLocaleString("en-US", {
20
+ minimumFractionDigits: 2,
21
+ maximumFractionDigits: 2,
22
+ }));
23
+ }
24
+ function formatPrice(tick) {
25
+ return "$" + tick.toLocaleString("en-US");
26
+ }
27
+ function formatPriceRange(lower, upper) {
28
+ const formatToK = (value) => {
29
+ if (value >= 1000)
30
+ return `$${(value / 1000).toFixed(1)}K`;
31
+ return `$${value}`;
32
+ };
33
+ return `${formatToK(lower)} - ${formatToK(upper)}`;
34
+ }
35
+ function percForm(value) {
36
+ const perc = Math.round(value * 10000) / 100;
37
+ return (perc.toLocaleString(undefined, {
38
+ minimumFractionDigits: 0,
39
+ maximumFractionDigits: 2,
40
+ }) + "%");
41
+ }
42
+ function formatUsdPnl(value) {
43
+ const abs = Math.abs(value);
44
+ const formatted = abs.toLocaleString("en-US", {
45
+ minimumFractionDigits: 2,
46
+ maximumFractionDigits: 2,
47
+ });
48
+ if (value === 0)
49
+ return `$${formatted}`;
50
+ return value > 0 ? `+$${formatted}` : `-$${formatted}`;
51
+ }
52
+ function getPnlColor(pnl, neutral) {
53
+ if (pnl === 0)
54
+ return neutral;
55
+ return pnl > 0 ? "#22c55e" : "#ef4444";
56
+ }
@@ -0,0 +1,2 @@
1
+ import type { SatoriNode } from "./types";
2
+ export declare function h(type: string, props: Record<string, unknown> | null, ...children: (SatoriNode | string)[]): SatoriNode;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.h = h;
4
+ function h(type, props, ...children) {
5
+ if (children.length === 0)
6
+ return { type, props: { ...props } };
7
+ if (children.length === 1)
8
+ return { type, props: { ...props, children: children[0] } };
9
+ return { type, props: { ...props, children } };
10
+ }
@@ -0,0 +1,8 @@
1
+ export type { SatoriNode, PositionImageInput, DistributionImageInput, PriceTick, BarCategory, } from "./types";
2
+ export { buildPositionVNode } from "./position-image";
3
+ export { buildDistributionVNode } from "./distribution-image";
4
+ export { buildBrandVNode } from "./brand-image";
5
+ export { h } from "./h";
6
+ export { SIGNALS_LOGO_URI, buildLogoStrokeSVG } from "./assets";
7
+ export { formatUSDC, formatPrice, formatPriceRange, percForm, formatUsdPnl, getPnlColor, } from "./format";
8
+ export { getBarCategory, getSqrtHeight, generateXAxisTicks, formatXTick, getPeakRange, formatDistributionPriceRange, } from "./distribution-share-utils";
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatDistributionPriceRange = exports.getPeakRange = exports.formatXTick = exports.generateXAxisTicks = exports.getSqrtHeight = exports.getBarCategory = exports.getPnlColor = exports.formatUsdPnl = exports.percForm = exports.formatPriceRange = exports.formatPrice = exports.formatUSDC = exports.buildLogoStrokeSVG = exports.SIGNALS_LOGO_URI = exports.h = exports.buildBrandVNode = exports.buildDistributionVNode = exports.buildPositionVNode = void 0;
4
+ // VNode builders
5
+ var position_image_1 = require("./position-image");
6
+ Object.defineProperty(exports, "buildPositionVNode", { enumerable: true, get: function () { return position_image_1.buildPositionVNode; } });
7
+ var distribution_image_1 = require("./distribution-image");
8
+ Object.defineProperty(exports, "buildDistributionVNode", { enumerable: true, get: function () { return distribution_image_1.buildDistributionVNode; } });
9
+ var brand_image_1 = require("./brand-image");
10
+ Object.defineProperty(exports, "buildBrandVNode", { enumerable: true, get: function () { return brand_image_1.buildBrandVNode; } });
11
+ // Helpers (used by v1-server for its own distribution rendering)
12
+ var h_1 = require("./h");
13
+ Object.defineProperty(exports, "h", { enumerable: true, get: function () { return h_1.h; } });
14
+ var assets_1 = require("./assets");
15
+ Object.defineProperty(exports, "SIGNALS_LOGO_URI", { enumerable: true, get: function () { return assets_1.SIGNALS_LOGO_URI; } });
16
+ Object.defineProperty(exports, "buildLogoStrokeSVG", { enumerable: true, get: function () { return assets_1.buildLogoStrokeSVG; } });
17
+ var format_1 = require("./format");
18
+ Object.defineProperty(exports, "formatUSDC", { enumerable: true, get: function () { return format_1.formatUSDC; } });
19
+ Object.defineProperty(exports, "formatPrice", { enumerable: true, get: function () { return format_1.formatPrice; } });
20
+ Object.defineProperty(exports, "formatPriceRange", { enumerable: true, get: function () { return format_1.formatPriceRange; } });
21
+ Object.defineProperty(exports, "percForm", { enumerable: true, get: function () { return format_1.percForm; } });
22
+ Object.defineProperty(exports, "formatUsdPnl", { enumerable: true, get: function () { return format_1.formatUsdPnl; } });
23
+ Object.defineProperty(exports, "getPnlColor", { enumerable: true, get: function () { return format_1.getPnlColor; } });
24
+ var distribution_share_utils_1 = require("./distribution-share-utils");
25
+ Object.defineProperty(exports, "getBarCategory", { enumerable: true, get: function () { return distribution_share_utils_1.getBarCategory; } });
26
+ Object.defineProperty(exports, "getSqrtHeight", { enumerable: true, get: function () { return distribution_share_utils_1.getSqrtHeight; } });
27
+ Object.defineProperty(exports, "generateXAxisTicks", { enumerable: true, get: function () { return distribution_share_utils_1.generateXAxisTicks; } });
28
+ Object.defineProperty(exports, "formatXTick", { enumerable: true, get: function () { return distribution_share_utils_1.formatXTick; } });
29
+ Object.defineProperty(exports, "getPeakRange", { enumerable: true, get: function () { return distribution_share_utils_1.getPeakRange; } });
30
+ Object.defineProperty(exports, "formatDistributionPriceRange", { enumerable: true, get: function () { return distribution_share_utils_1.formatDistributionPriceRange; } });
@@ -0,0 +1,2 @@
1
+ import type { SatoriNode, PositionImageInput } from "./types";
2
+ export declare function buildPositionVNode(input: PositionImageInput): SatoriNode;