Hyperscalper is een professionele cryptocurrency trading terminal die ik bouwde voor Hyperliquid DEX. Wat het uniek maakt is dat het volledig client-side is — geen backend servers, geen tussenpersonen. Je private keys verlaten nooit je browser.

In deze post loop ik door de belangrijkste architecturale beslissingen, de verschillende ordermethoden die ik implementeerde, en hoe de realtime markt-scanners werken.
Waarom Volledig Client-Side?
Bij het bouwen van een trading-applicatie die private keys beheert, is vertrouwen alles. Ik maakte een bewuste keuze: zero backend.
Het Vertrouwensprobleem
Traditionele tradingplatformen vereisen dat je hen je inloggegevens toevertrouwt. Zelfs met de beste beveiligingspraktijken is er altijd een server die gecompromitteerd kan worden, een database die gelekt kan worden, of een medewerker die kwaad in de zin heeft.
Met Hyperscalper is de datastroom simpel:
Browser → Hyperliquid DEX API
Dat is het. Geen relay servers, geen proxies, geen backend databases.
Hoe Private Keys Beveiligd Worden
Hoewel alles in de browser draait, had ik toch robuuste encryptie nodig voor de private key die in localStorage wordt opgeslagen. Dit is de aanpak:
// AES-GCM encryptie met PBKDF2 key derivationConst deriveKey = async (password: string, salt: Uint8Array) => {const keyMaterial = await crypto.subtle.importKey('raw',new TextEncoder().encode(password),'PBKDF2',false,['deriveBits', 'deriveKey']);return crypto.subtle.deriveKey({name: 'PBKDF2',salt,iterations: 100000, // Maakt brute-force duurhash: 'SHA-256'},keyMaterial,{ name: 'AES-GCM', length: 256 },false,['encrypt', 'decrypt']);};
Het systeem genereert bij eerste gebruik een apparaat-specifieke sleutel, opgeslagen in localStorage. Gebruikers kunnen optioneel een wachtwoord toevoegen voor extra bescherming. Zelfs als iemand de localStorage-data steelt, hebben ze 100.000 PBKDF2-iteraties nodig om elke gok te kraken.
De Afwegingen
Volledig client-side gaan heeft consequenties:
- Zero vertrouwen vereist — maar je kunt geen server-side bots draaien
- Geen dataverzameling — maar ordergeschiedenis is afhankelijk van de exchange API
- Echte decentralisatie — maar alle berekeningen gebeuren in de browser
- Geen serverkosten — maar je kunt geen zware backtesting doen
Voor een scalping terminal waar snelheid ertoe doet, zijn deze afwegingen logisch. De latency (vertraging) tussen je browser en Hyperliquid is het enige dat telt.
Ordermethoden
Traders hebben verschillende workflows. Sommigen klikken het liefst, anderen gebruiken sneltoetsen, en weer anderen willen geautomatiseerde ladder orders. Ik implementeerde vijf verschillende manieren om orders in te voeren.
Click-on-Chart Orders
Soms wil je een order plaatsen op een specifiek prijsniveau dat je op de chart ziet. Ik implementeerde een crosshair-systeem dat dit intuïtief maakt:

Const handleChartClick = (params) => {if (!crosshairActive) return;const price = params.price;const isBuy = price < currentPrice;placeLimitOrderAtPrice({symbol,price,isBuy,percentage: settings.orderSizePercent});setCrosshairActive(false);};
Klik onder de huidige prijs = koop limit order. Klik erboven = verkoop limit order. Simpel en intuïtief.
Cloud Ladder Orders (DCA)
De kenmerkende feature. In plaats van één enkele order te plaatsen, plaatst Cloud orders 5 limit orders gestapeld op intervallen onder (voor kooporders) of boven (voor verkooporders) de huidige prijs.
Const buyCloud = async ({ symbol, currentPrice, priceInterval, percentage }) => {const ORDER_COUNT = 5;const TAKE_PROFIT_PERCENT = 2;const orders = [];for (let I = 0; I < ORDER_COUNT; I++) {const price = currentPrice - (priceInterval * I);const size = totalSize / ORDER_COUNT;orders.push({type: 'limit',side: 'buy',price,size,reduceOnly: false});// Auto TP op 2% winstorders.push({type: 'limit',side: 'sell',price: price * (1 + TAKE_PROFIT_PERCENT / 100),size,reduceOnly: true});}await Promise.all(orders.map(o => submitOrder(o)));};
Het prijsinterval wordt berekend op basis van recente kaarshoogtes — het systeem past zich aan de huidige volatiliteit aan.
Sneltoetsen
Voor snelheidstraders is naar de muis grijpen te langzaam. Ik koppelde alle veelgebruikte acties aan hotkeys:

UseEffect(() => {const handleKeyDown = (e: KeyboardEvent) => {if (e.metaKey || e.ctrlKey) {switch (e.key) {case 'b':e.preventDefault();inverted ? SellCloud() : buyCloud();break;case 's':e.preventDefault();inverted ? BuyCloud() : sellCloud();break;case 'e':e.preventDefault();closePosition(25); // Sluit 25%break;}}};window.addEventListener('keydown', handleKeyDown);return () => window.removeEventListener('keydown', handleKeyDown);}, [inverted]);
Let op de inverted check — daar kom ik later op terug.
Optimistic Updates
Niemand wil 500ms wachten op een API-respons voordat ze feedback zien. Ik implementeerde optimistic updates (optimistische bijwerkingen):
Const placeOrder = async (order) => {// 1. Direct tonen in UIconst optimisticId = crypto.randomUUID();addOptimisticOrder({ ...order, id: optimisticId });showToast('Placing order...');try {// 2. Daadwerkelijk indienen bij de exchangeconst result = await submitToHyperliquid(order);// 3. Optimistisch vervangen door echtremoveOptimisticOrder(optimisticId);addConfirmedOrder(result);playSuccessSound();} catch (error) {// 4. Terugdraaien bij foutremoveOptimisticOrder(optimisticId);showErrorToast(error.message);}};
De UI reageert in minder dan 100ms, ongeacht netwerklatency.
Markt-Scanners
Een trading terminal is slechts zo goed als zijn vermogen om kansen te vinden. Ik bouwde 8 verschillende scannertypes die in realtime draaien over alle symbolen.

Scanner-Architectuur
Elke scanner abonneert zich op candle data via WebSocket en voert analyse uit bij elke update:
// Gedeelde WebSocket-verbinding (singleton pattern)Const ws = getWebSocketService();// Abonneer op alle symbolen op meerdere timeframesSymbols.forEach(symbol => {['1m', '5m', '15m', '1h'].forEach(timeframe => {ws.subscribeToCandles(symbol, timeframe, (candles) => {runScanners(symbol, timeframe, candles);});});});
Stochastic Scanner
De stochastic oscillator is uitstekend voor het vinden van oversold/overbought (oververkocht/overkocht) condities. Ik implementeerde vier varianten met verschillende periodes:
Const scanStochastic = (candles, config) => {const variants = {ultraFast: { period: 5, smoothK: 2, smoothD: 2 },fast: { period: 9, smoothK: 3, smoothD: 3 },medium: { period: 14, smoothK: 3, smoothD: 3 },slow: { period: 21, smoothK: 5, smoothD: 5 }};const signals = [];Object.entries(variants).forEach(([name, params]) => {if (!config.variants[name].enabled) return;const stoch = calculateStochastic(candles, params);const current = stoch[stoch.length - 1];const previous = stoch[stoch.length - 2];// Bullish: K kruist boven D in oversold zoneif (current.k > current.d &&previous.k <= previous.d &¤t.k < config.oversoldLevel) {signals.push({type: 'stochastic',variant: name,direction: 'bullish',strength: (config.oversoldLevel - current.k) / config.oversoldLevel});}});return signals;};
Divergentie-Detectie
Divergenties zijn krachtige signalen — wanneer de prijs een nieuw dieptepunt maakt maar de RSI een hoger dieptepunt, duidt dat vaak op een ommekeer. Dit vereiste complexere logica:
Const detectDivergence = (candles, rsiValues) => {const pricePivots = findPivots(candles, 3);const rsiPivots = findPivots(rsiValues, 3);const divergences = [];const recentPriceLows = pricePivots.filter(p => p.type === 'low').slice(-5);for (let I = 1; I < recentPriceLows.length; I++) {const current = recentPriceLows[I];const previous = recentPriceLows[I - 1];// Prijs maakte een lager dieptepuntif (current.price < previous.price) {const currentRsi = findClosestPivot(rsiPivots, current.index);const previousRsi = findClosestPivot(rsiPivots, previous.index);// RSI maakte een hoger dieptepunt = bullish divergentieif (currentRsi.value > previousRsi.value) {divergences.push({type: 'regular_bullish',pricePoints: [previous, current],rsiPoints: [previousRsi, currentRsi],strength: calculateDivergenceStrength(...)});}}}return divergences;};
Prestatieoverwegingen
8 scanners draaien over 500+ symbolen op 4 timeframes zou de browserprestaties makkelijk kunnen killen. Ik gebruikte verschillende optimalisatietechnieken:
Memoization met TTL:
Const memoizedCalculate = createMemoizedFunction(calculateStochastic,(candles, period) => `stoch-${candles.length}-${period}`,100, // max cache entries60000 // vervalt na 60s);
Debounced divergentie-detectie:
// Herbereken niet bij elke tickConst debouncedDivergence = useDebouncedCallback(detectDivergence,1000 // Wacht 1s na laatste update);
Virtual scrolling voor resultaten:
<FixedSizeListheight={600}itemCount={signals.length}itemSize={60}>{({ index, style }) => (<SignalItem signal={signals[index]} style={style} />)}</FixedSizeList>
Multi-Timeframe Analyse
Een van de krachtigste features is het multi-timeframe overzicht. Hetzelfde symbool tegelijk zien op 1m, 5m, 15m en 1u helpt bij het identificeren van confluence (samenvloeiing van signalen).

Alle charts zijn gesynchroniseerd — wanneer je op één chart zoomt of schuift, volgen alle andere. Dit wordt bereikt via een gedeelde chart sync store:
Const useChartSyncStore = create((set) => ({timeRange: null,setTimeRange: (range) => set({ timeRange: range }),}));// In elke chart-componentUseEffect(() => {const unsubscribe = useChartSyncStore.subscribe((state) => state.timeRange,(range) => {if (range) chart.timeScale().setVisibleRange(range);});return unsubscribe;}, [chart]);
Support en Resistance Lijnen
Geautomatiseerde trendlijn-detectie is een van die features die simpel klinkt maar verrassend diep gaat. Ik implementeerde drie complementaire benaderingen.
Pivot-Gebaseerde Trendlijnen
De meest intuïtieve aanpak: vind pivotpunten en trek er lijnen doorheen.
Const detectPivots = (candles, strength = 3) => {const pivots = [];for (let I = strength; I < candles.length - strength; I++) {const current = candles[I];let isHigh = true;for (let j = I - strength; j <= I + strength; j++) {if (j !== I && candles[j].high >= current.high) {isHigh = false;break;}}if (isHigh) {pivots.push({ index: I, price: current.high, type: 'high' });}// Dezelfde logica voor dieptepunten...}return pivots;};
Envelope Validatie
Een supportlijn die doorbroken wordt is niet nuttig. Ik valideer lijnen tegen alle candles:
Const findBestSupportLine = (pivots, candles) => {let bestLine = null;let bestScore = -Infinity;for (let I = 0; I < pivots.length - 1; I++) {for (let j = I + 1; j < pivots.length; j++) {const line = createLine(pivots[I], pivots[j]);let touches = 0;let violations = 0;candles.forEach((candle, idx) => {const linePrice = getLineValueAt(line, idx);const tolerance = linePrice * 0.002;if (candle.low < linePrice - tolerance) {violations++;} else if (Math.abs(candle.low - linePrice) < tolerance) {touches++;}});const score = touches * 10 - violations * 100;if (score > bestScore && violations === 0 && touches >= 3) {bestScore = score;bestLine = line;}}}return bestLine;};
Het belangrijkste inzicht: een supportlijn met nul doorbraken is veel waardevoller dan eentje met veel raakpunten maar enkele doorbraken.
Trade-Analyse
Prestaties bijhouden is essentieel om te verbeteren als trader. Hyperscalper biedt dagelijkse en maandelijkse P&L-overzichten (winst en verlies):


Al deze data komt rechtstreeks van Hyperliquid's API — geen backend-opslag nodig.
De Inverted Modus
Dit is een feature geboren uit echte trading-ervaring: inverted mode (omgekeerde modus).
Als je een short-biased trader bent, is de standaard UI verwarrend. Groen betekent dat de prijs omhoog ging (slecht voor shorts), rood betekent dat het omlaag ging (goed voor shorts). Bullish signalen zijn bearish kansen.
Inverted mode draait alles om:
Const getSignalColor = (signal, inverted) => {const isBullish = signal.direction === 'bullish';if (inverted) {// Bullish signaal = shortkans = toon als "goed" (groen)return isBullish ? Colors.bearish : colors.bullish;}return isBullish ? Colors.bullish : colors.bearish;};
Kaarskleuren, signaalindicatoren, zelfs de support/resistance label-semantiek draait om. Een short trader ziet dezelfde patronen als een long trader, alleen correct geïnterpreteerd voor zijn bias.
Multi-Monitor Ondersteuning
Professionele traders gebruiken vaak meerdere monitoren. Hyperscalper ondersteunt het losmaken van charts in aparte vensters:

Elk popup-venster behoudt zijn eigen WebSocket-verbinding en synchroniseert state met het hoofdvenster via BroadcastChannel:
Const channel = new BroadcastChannel('hyperscalper-sync');// Hoofdvenster broadcast statuswijzigingenChannel.postMessage({ type: 'POSITION_UPDATE', data: positions });// Popup-vensters luisterenChannel.onmessage = (event) => {if (event.data.type === 'POSITION_UPDATE') {setPositions(event.data.data);}};
State Management met Zustand
Met 20+ stores die verschillende domeinen beheren, had ik lichtgewicht state management nodig. Redux voelde als overkill. Ik koos Zustand:
Const useTradingStore = create<TradingStore>((set, get) => ({orders: [],positions: [],addOrder: (order) => set((state) => ({orders: [...state.orders, order]})),closePosition: async (symbol, percentage) => {const position = get().positions.find(p => p.symbol === symbol);if (!position) return;const size = position.size * (percentage / 100);await submitMarketOrder({symbol,side: position.side === 'long' ? 'sell' : 'buy',size,reduceOnly: true});}}));
Elke store is gericht op één domein: trading, orders, posities, candles, scanner, instellingen, etc. Componenten abonneren zich op precies wat ze nodig hebben.
Lessen Geleerd
Het bouwen van Hyperscalper leerde me verschillende dingen:
1. Client-side kan genoeg zijn. Voor applicaties waar vertrouwen ertoe doet, is het elimineren van de backend niet alleen mogelijk — het verdient de voorkeur.
2. Optimistic updates zijn essentieel. Bij trading voelt 500ms latency als een eeuwigheid. Toon direct feedback, reconcilieer later.
3. Meerdere invoermethoden doen ertoe. Verschillende traders hebben verschillende workflows. Sommigen klikken, sommigen gebruiken sneltoetsen, sommigen willen automatisering. Ondersteun ze allemaal.
4. Prestatie-optimalisatie is verplicht. Technische analyse draaien op 500 symbolen in realtime vereist zorgvuldige aandacht voor memoization, debouncing en virtual rendering.
5. Omgekeerd denken helpt. Bouwen voor short traders dwong me om aannames te bevragen over wat „omhoog" en „goed" betekenen. Het resultaat is een flexibeler systeem.
Hyperscalper is live op hyperscalper.vercel.app als je het wilt uitproberen. De code laat zien dat professionele tradingtools volledig in de browser kunnen draaien — geen backend vereist.
Stay Updated
Get notified about new posts on automation, productivity tips, indie hacking, and web3.
No spam, ever. Unsubscribe anytime.



