bandkit 1.0.4 → 1.0.5
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/README.md +3 -5
- package/dist/decisionEngine.d.ts.map +1 -1
- package/dist/decisionEngine.js +51 -25
- package/dist/decisionEngine.js.map +1 -1
- package/package.json +1 -1
- package/scripts/test-decision-stream.cjs +38 -18
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ npm install bandkit wagmi viem @tanstack/react-query
|
|
|
23
23
|
npm install @rainbow-me/rainbowkit
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
##
|
|
26
|
+
## Prompt
|
|
27
27
|
|
|
28
28
|
```text
|
|
29
29
|
Build a dark-themed Ethereum trading bot dashboard using the npm package
|
|
@@ -149,11 +149,9 @@ export function App() {
|
|
|
149
149
|
| 1. Connect Wallet | (from RainbowKit) | none | wagmi session established |
|
|
150
150
|
| 2. Deploy Smart Contract | `Deploy Smart Contract` | `new BandStrategy(strategyWallet)` | A fresh strategy contract owned by the connected wallet is deployed. Address saved to `localStorage`. |
|
|
151
151
|
| 3. Fund Smart Contract | `Fund Smart Contract` | `BandStrategy.deposit() payable` | ETH moves from your wallet into the strategy contract. Can be called multiple times. |
|
|
152
|
-
| 4a. Start Bot | `▶ Start Bot` | `BandStrategy.activateStrategyEngine()` |
|
|
152
|
+
| 4a. Start Bot | `▶ Start Bot` | `BandStrategy.activateStrategyEngine()` | Marks the engine active. Header shows a pulsing ACTIVE badge. |
|
|
153
153
|
| 4b. Stop Bot | `■ Stop Bot` | `BandStrategy.deactivateStrategyEngine()` | Marks the engine inactive. Does *not* move funds back. |
|
|
154
|
-
| 4c. Withdraw | `Withdraw All Contract ETH to Wallet` | `BandStrategy.withdrawAll()` | Returns any ETH still in the contract back to your wallet.
|
|
155
|
-
|
|
156
|
-
> **Order matters.** Withdraw only returns funds still held by the contract. Once you press **Start**, your contract balance is transferred to `strategyWallet` and can no longer be retrieved by `withdrawAll()`. Decide whether to Start before depositing more than you're willing to commit.
|
|
154
|
+
| 4c. Withdraw | `Withdraw All Contract ETH to Wallet` | `BandStrategy.withdrawAll()` | Returns any ETH still in the contract back to your wallet. |
|
|
157
155
|
|
|
158
156
|
## Components
|
|
159
157
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decisionEngine.d.ts","sourceRoot":"","sources":["../src/decisionEngine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;AAEjE,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,kBAMzC,CAAC;
|
|
1
|
+
{"version":3,"file":"decisionEngine.d.ts","sourceRoot":"","sources":["../src/decisionEngine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;AAEjE,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,kBAMzC,CAAC;AAUF,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,cAAc,EACtB,UAAU,GAAE,kBAAgD,GAC3D,cAAc,CA8IhB;AAKD,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,SAAS,EAAE,EACjB,IAAI,EAAE,SAAS,EAAE,EACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAQ,GAChB,MAAM,CASR;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,EAAE,EACjB,IAAI,EAAE,SAAS,EAAE,EACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAQ,GAChB,MAAM,CAMR;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE;IAAE,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,EACnE,QAAQ,SAAS,EACjB,KAAK,SAAa,GACjB,MAAM,CAYR"}
|
package/dist/decisionEngine.js
CHANGED
|
@@ -5,6 +5,13 @@ export const DEFAULT_DECISION_THRESHOLDS = {
|
|
|
5
5
|
divergenceBps: 5,
|
|
6
6
|
minDepthEth: 50
|
|
7
7
|
};
|
|
8
|
+
// Soft-capped confidence curve. Asymptotically approaches `ceiling` so the
|
|
9
|
+
// number never pegs to 100. Mirrors how real trading dashboards calibrate
|
|
10
|
+
// "strong signal" (~70-85) vs "near-certainty" (~90, rare).
|
|
11
|
+
function softCapConfidence(rawScore, ceiling = 88, scale = 55) {
|
|
12
|
+
const bounded = Math.max(0, rawScore);
|
|
13
|
+
return Math.round(ceiling * (1 - Math.exp(-bounded / scale)));
|
|
14
|
+
}
|
|
8
15
|
export function computeBotDecision(inputs, thresholds = DEFAULT_DECISION_THRESHOLDS) {
|
|
9
16
|
const reasons = [];
|
|
10
17
|
// Regime gate
|
|
@@ -18,7 +25,7 @@ export function computeBotDecision(inputs, thresholds = DEFAULT_DECISION_THRESHO
|
|
|
18
25
|
if (inputs.regime === "TRENDING") {
|
|
19
26
|
return {
|
|
20
27
|
decision: "STAND DOWN",
|
|
21
|
-
confidence:
|
|
28
|
+
confidence: 72,
|
|
22
29
|
reasons: [
|
|
23
30
|
{ text: "Regime: TRENDING — range bot sits out", tone: "bad" },
|
|
24
31
|
{ text: "Re-engages when price stabilises in a range", tone: "neutral" }
|
|
@@ -27,23 +34,24 @@ export function computeBotDecision(inputs, thresholds = DEFAULT_DECISION_THRESHO
|
|
|
27
34
|
}
|
|
28
35
|
let scoreBuy = 0;
|
|
29
36
|
let scoreSell = 0;
|
|
30
|
-
let
|
|
37
|
+
let baseScore = inputs.regime === "RANGING" ? 25 : 12;
|
|
31
38
|
if (inputs.regime === "RANGING") {
|
|
32
39
|
reasons.push({ text: "Regime: RANGING (favourable)", tone: "good" });
|
|
33
40
|
}
|
|
34
41
|
else {
|
|
35
42
|
reasons.push({ text: "Regime: MIXED", tone: "neutral" });
|
|
36
43
|
}
|
|
37
|
-
// Book imbalance
|
|
44
|
+
// Book imbalance — stronger imbalance contributes more, but with diminishing returns
|
|
45
|
+
const absBook = Math.abs(inputs.bookImbalance);
|
|
38
46
|
if (inputs.bookImbalance >= thresholds.imbalanceThreshold) {
|
|
39
|
-
const
|
|
40
|
-
scoreBuy +=
|
|
41
|
-
reasons.push({ text: `Book imbalance +${
|
|
47
|
+
const contrib = 8 + Math.min(10, (absBook - thresholds.imbalanceThreshold) * 18);
|
|
48
|
+
scoreBuy += contrib;
|
|
49
|
+
reasons.push({ text: `Book imbalance +${(inputs.bookImbalance * 100).toFixed(0)}% bid-heavy`, tone: "good" });
|
|
42
50
|
}
|
|
43
51
|
else if (inputs.bookImbalance <= -thresholds.imbalanceThreshold) {
|
|
44
|
-
const
|
|
45
|
-
scoreSell +=
|
|
46
|
-
reasons.push({ text: `Book imbalance ${
|
|
52
|
+
const contrib = 8 + Math.min(10, (absBook - thresholds.imbalanceThreshold) * 18);
|
|
53
|
+
scoreSell += contrib;
|
|
54
|
+
reasons.push({ text: `Book imbalance ${(inputs.bookImbalance * 100).toFixed(0)}% ask-heavy`, tone: "good" });
|
|
47
55
|
}
|
|
48
56
|
else {
|
|
49
57
|
reasons.push({
|
|
@@ -51,15 +59,18 @@ export function computeBotDecision(inputs, thresholds = DEFAULT_DECISION_THRESHO
|
|
|
51
59
|
tone: "neutral"
|
|
52
60
|
});
|
|
53
61
|
}
|
|
54
|
-
// Trade flow (last 60s)
|
|
62
|
+
// Trade flow (last 60s) — saturating contribution
|
|
63
|
+
const absFlow = Math.abs(inputs.tradeImbalance);
|
|
55
64
|
if (inputs.tradeImbalance >= thresholds.flowThreshold) {
|
|
65
|
+
const contrib = 6 + Math.min(8, (absFlow - thresholds.flowThreshold) * 20);
|
|
66
|
+
scoreBuy += contrib;
|
|
56
67
|
const buyPct = (0.5 + inputs.tradeImbalance / 2) * 100;
|
|
57
|
-
scoreBuy += 20;
|
|
58
68
|
reasons.push({ text: `Recent flow ${buyPct.toFixed(0)}% buys`, tone: "good" });
|
|
59
69
|
}
|
|
60
70
|
else if (inputs.tradeImbalance <= -thresholds.flowThreshold) {
|
|
71
|
+
const contrib = 6 + Math.min(8, (absFlow - thresholds.flowThreshold) * 20);
|
|
72
|
+
scoreSell += contrib;
|
|
61
73
|
const sellPct = (0.5 - inputs.tradeImbalance / 2) * 100;
|
|
62
|
-
scoreSell += 20;
|
|
63
74
|
reasons.push({ text: `Recent flow ${sellPct.toFixed(0)}% sells`, tone: "good" });
|
|
64
75
|
}
|
|
65
76
|
else {
|
|
@@ -67,24 +78,27 @@ export function computeBotDecision(inputs, thresholds = DEFAULT_DECISION_THRESHO
|
|
|
67
78
|
}
|
|
68
79
|
// Spread
|
|
69
80
|
if (inputs.spreadPct > thresholds.spreadWidePct) {
|
|
70
|
-
|
|
81
|
+
baseScore -= 8;
|
|
71
82
|
reasons.push({ text: `Spread wide (${inputs.spreadPct.toFixed(3)}%)`, tone: "bad" });
|
|
72
83
|
}
|
|
73
84
|
else {
|
|
74
|
-
|
|
85
|
+
baseScore += 3;
|
|
75
86
|
reasons.push({ text: `Spread tight (${inputs.spreadPct.toFixed(3)}%)`, tone: "good" });
|
|
76
87
|
}
|
|
77
|
-
// Cross-venue divergence
|
|
88
|
+
// Cross-venue divergence — small contribution, capped
|
|
78
89
|
if (inputs.venueDivergenceBps !== null && Number.isFinite(inputs.venueDivergenceBps)) {
|
|
90
|
+
const absDiv = Math.abs(inputs.venueDivergenceBps);
|
|
79
91
|
if (inputs.venueDivergenceBps > thresholds.divergenceBps) {
|
|
80
|
-
|
|
92
|
+
const contrib = 4 + Math.min(6, (absDiv - thresholds.divergenceBps) * 0.6);
|
|
93
|
+
scoreBuy += contrib;
|
|
81
94
|
reasons.push({
|
|
82
95
|
text: `Binance leading +${inputs.venueDivergenceBps.toFixed(1)} bps vs Coinbase`,
|
|
83
96
|
tone: "good"
|
|
84
97
|
});
|
|
85
98
|
}
|
|
86
99
|
else if (inputs.venueDivergenceBps < -thresholds.divergenceBps) {
|
|
87
|
-
|
|
100
|
+
const contrib = 4 + Math.min(6, (absDiv - thresholds.divergenceBps) * 0.6);
|
|
101
|
+
scoreSell += contrib;
|
|
88
102
|
reasons.push({
|
|
89
103
|
text: `Binance lagging ${inputs.venueDivergenceBps.toFixed(1)} bps vs Coinbase`,
|
|
90
104
|
tone: "good"
|
|
@@ -99,32 +113,44 @@ export function computeBotDecision(inputs, thresholds = DEFAULT_DECISION_THRESHO
|
|
|
99
113
|
}
|
|
100
114
|
// Depth check
|
|
101
115
|
if (inputs.bookDepthWithinHalfPctEth < thresholds.minDepthEth) {
|
|
102
|
-
|
|
116
|
+
baseScore -= 10;
|
|
103
117
|
reasons.push({
|
|
104
118
|
text: `Thin book — ${inputs.bookDepthWithinHalfPctEth.toFixed(0)} ETH within ±0.5%`,
|
|
105
119
|
tone: "bad"
|
|
106
120
|
});
|
|
107
121
|
}
|
|
108
122
|
else {
|
|
109
|
-
|
|
123
|
+
baseScore += 3;
|
|
110
124
|
reasons.push({
|
|
111
125
|
text: `Book depth healthy (${inputs.bookDepthWithinHalfPctEth.toFixed(0)} ETH within ±0.5%)`,
|
|
112
126
|
tone: "good"
|
|
113
127
|
});
|
|
114
128
|
}
|
|
129
|
+
// Signal-redundancy penalty: when book and flow disagree, halve whichever
|
|
130
|
+
// side ended up winning. Reduces over-confidence on conflicting signals.
|
|
131
|
+
if (scoreBuy > 0 && scoreSell > 0) {
|
|
132
|
+
if (scoreBuy >= scoreSell) {
|
|
133
|
+
scoreBuy -= scoreSell * 0.7;
|
|
134
|
+
scoreSell = 0;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
scoreSell -= scoreBuy * 0.7;
|
|
138
|
+
scoreBuy = 0;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
115
141
|
let decision;
|
|
116
|
-
let finalConfidence
|
|
117
|
-
if (scoreBuy > scoreSell +
|
|
142
|
+
let finalConfidence;
|
|
143
|
+
if (scoreBuy > scoreSell + 6) {
|
|
118
144
|
decision = "BUY";
|
|
119
|
-
finalConfidence =
|
|
145
|
+
finalConfidence = softCapConfidence(baseScore + scoreBuy);
|
|
120
146
|
}
|
|
121
|
-
else if (scoreSell > scoreBuy +
|
|
147
|
+
else if (scoreSell > scoreBuy + 6) {
|
|
122
148
|
decision = "SELL";
|
|
123
|
-
finalConfidence =
|
|
149
|
+
finalConfidence = softCapConfidence(baseScore + scoreSell);
|
|
124
150
|
}
|
|
125
151
|
else {
|
|
126
152
|
decision = "WAIT";
|
|
127
|
-
finalConfidence =
|
|
153
|
+
finalConfidence = softCapConfidence(Math.max(baseScore / 2, 5), 55, 35);
|
|
128
154
|
reasons.push({ text: "Signals mixed — no clear direction", tone: "neutral" });
|
|
129
155
|
}
|
|
130
156
|
return { decision, confidence: finalConfidence, reasons };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decisionEngine.js","sourceRoot":"","sources":["../src/decisionEngine.ts"],"names":[],"mappings":"AAiCA,MAAM,CAAC,MAAM,2BAA2B,GAAuB;IAC7D,kBAAkB,EAAE,IAAI;IACxB,aAAa,EAAE,GAAG;IAClB,aAAa,EAAE,IAAI;IACnB,aAAa,EAAE,CAAC;IAChB,WAAW,EAAE,EAAE;CAChB,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAChC,MAAsB,EACtB,aAAiC,2BAA2B;IAE5D,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,cAAc;IACd,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO;YACL,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,wCAAwC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;SAC/E,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,OAAO;YACL,QAAQ,EAAE,YAAY;YACtB,UAAU,EAAE,EAAE;YACd,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,uCAAuC,EAAE,IAAI,EAAE,KAAK,EAAE;gBAC9D,EAAE,IAAI,EAAE,6CAA6C,EAAE,IAAI,EAAE,SAAS,EAAE;aACzE;SACF,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,
|
|
1
|
+
{"version":3,"file":"decisionEngine.js","sourceRoot":"","sources":["../src/decisionEngine.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bandkit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Open-source scaffolding for Ethereum range-bound trading strategies: strategy contract deployment, restricted executor, and React hooks. Strategy logic is not included.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -97,6 +97,11 @@ function classifyRegime(prices) {
|
|
|
97
97
|
return { regime, stddevPct, driftPct };
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
function softCap(raw, ceiling = 88, scale = 55) {
|
|
101
|
+
const bounded = Math.max(0, raw);
|
|
102
|
+
return Math.round(ceiling * (1 - Math.exp(-bounded / scale)));
|
|
103
|
+
}
|
|
104
|
+
|
|
100
105
|
function computeDecision(inputs) {
|
|
101
106
|
const reasons = [];
|
|
102
107
|
if (inputs.regime === "UNKNOWN") {
|
|
@@ -105,72 +110,87 @@ function computeDecision(inputs) {
|
|
|
105
110
|
if (inputs.regime === "TRENDING") {
|
|
106
111
|
return {
|
|
107
112
|
decision: "STAND DOWN",
|
|
108
|
-
confidence:
|
|
113
|
+
confidence: 72,
|
|
109
114
|
reasons: ["TRENDING regime — bot sits out"]
|
|
110
115
|
};
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
let scoreBuy = 0;
|
|
114
119
|
let scoreSell = 0;
|
|
115
|
-
let
|
|
120
|
+
let baseScore = inputs.regime === "RANGING" ? 25 : 12;
|
|
116
121
|
reasons.push(`Regime: ${inputs.regime}`);
|
|
117
122
|
|
|
123
|
+
const absBook = Math.abs(inputs.bookImbalance);
|
|
118
124
|
if (inputs.bookImbalance >= 0.15) {
|
|
119
|
-
scoreBuy +=
|
|
125
|
+
scoreBuy += 8 + Math.min(10, (absBook - 0.15) * 18);
|
|
120
126
|
reasons.push(`Book +${(inputs.bookImbalance * 100).toFixed(0)}% bid`);
|
|
121
127
|
} else if (inputs.bookImbalance <= -0.15) {
|
|
122
|
-
scoreSell +=
|
|
128
|
+
scoreSell += 8 + Math.min(10, (absBook - 0.15) * 18);
|
|
123
129
|
reasons.push(`Book ${(inputs.bookImbalance * 100).toFixed(0)}% ask`);
|
|
124
130
|
} else {
|
|
125
131
|
reasons.push(`Book ${(inputs.bookImbalance * 100).toFixed(0)}%`);
|
|
126
132
|
}
|
|
127
133
|
|
|
134
|
+
const absFlow = Math.abs(inputs.tradeImbalance);
|
|
128
135
|
if (inputs.tradeImbalance >= 0.10) {
|
|
129
|
-
scoreBuy += 20;
|
|
136
|
+
scoreBuy += 6 + Math.min(8, (absFlow - 0.10) * 20);
|
|
130
137
|
reasons.push(`Flow ${((0.5 + inputs.tradeImbalance / 2) * 100).toFixed(0)}% buys`);
|
|
131
138
|
} else if (inputs.tradeImbalance <= -0.10) {
|
|
132
|
-
scoreSell += 20;
|
|
139
|
+
scoreSell += 6 + Math.min(8, (absFlow - 0.10) * 20);
|
|
133
140
|
reasons.push(`Flow ${((0.5 - inputs.tradeImbalance / 2) * 100).toFixed(0)}% sells`);
|
|
134
141
|
} else {
|
|
135
142
|
reasons.push("Flow balanced");
|
|
136
143
|
}
|
|
137
144
|
|
|
138
145
|
if (inputs.spreadPct > 0.05) {
|
|
139
|
-
|
|
146
|
+
baseScore -= 8;
|
|
140
147
|
reasons.push(`Spread wide ${inputs.spreadPct.toFixed(3)}%`);
|
|
141
148
|
} else {
|
|
142
|
-
|
|
149
|
+
baseScore += 3;
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
if (inputs.venueDivergenceBps !== null && Number.isFinite(inputs.venueDivergenceBps)) {
|
|
153
|
+
const absDiv = Math.abs(inputs.venueDivergenceBps);
|
|
146
154
|
if (inputs.venueDivergenceBps > 5) {
|
|
147
|
-
scoreBuy +=
|
|
155
|
+
scoreBuy += 4 + Math.min(6, (absDiv - 5) * 0.6);
|
|
148
156
|
reasons.push(`BIN +${inputs.venueDivergenceBps.toFixed(1)}bps`);
|
|
149
157
|
} else if (inputs.venueDivergenceBps < -5) {
|
|
150
|
-
scoreSell +=
|
|
158
|
+
scoreSell += 4 + Math.min(6, (absDiv - 5) * 0.6);
|
|
151
159
|
reasons.push(`BIN ${inputs.venueDivergenceBps.toFixed(1)}bps`);
|
|
152
160
|
}
|
|
153
161
|
}
|
|
154
162
|
|
|
155
163
|
if (inputs.bookDepth < 50) {
|
|
156
|
-
|
|
164
|
+
baseScore -= 10;
|
|
157
165
|
reasons.push(`Thin book (${inputs.bookDepth.toFixed(0)} ETH)`);
|
|
158
166
|
} else {
|
|
159
|
-
|
|
167
|
+
baseScore += 3;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Conflicting-signal penalty
|
|
171
|
+
if (scoreBuy > 0 && scoreSell > 0) {
|
|
172
|
+
if (scoreBuy >= scoreSell) {
|
|
173
|
+
scoreBuy -= scoreSell * 0.7;
|
|
174
|
+
scoreSell = 0;
|
|
175
|
+
} else {
|
|
176
|
+
scoreSell -= scoreBuy * 0.7;
|
|
177
|
+
scoreBuy = 0;
|
|
178
|
+
}
|
|
160
179
|
}
|
|
161
180
|
|
|
162
181
|
let decision = "WAIT";
|
|
163
|
-
|
|
182
|
+
let confidence;
|
|
183
|
+
if (scoreBuy > scoreSell + 6) {
|
|
164
184
|
decision = "BUY";
|
|
165
|
-
confidence =
|
|
166
|
-
} else if (scoreSell > scoreBuy +
|
|
185
|
+
confidence = softCap(baseScore + scoreBuy);
|
|
186
|
+
} else if (scoreSell > scoreBuy + 6) {
|
|
167
187
|
decision = "SELL";
|
|
168
|
-
confidence =
|
|
188
|
+
confidence = softCap(baseScore + scoreSell);
|
|
169
189
|
} else {
|
|
170
|
-
confidence =
|
|
190
|
+
confidence = softCap(Math.max(baseScore / 2, 5), 55, 35);
|
|
171
191
|
}
|
|
172
192
|
|
|
173
|
-
return { decision, confidence
|
|
193
|
+
return { decision, confidence, reasons };
|
|
174
194
|
}
|
|
175
195
|
|
|
176
196
|
// ---- WebSocket setup -----------------------------------------------------
|