Skip to main content

Welcome to Wisp SDK

Wisp SDK is a production-grade, event-driven trading framework for building autonomous trading strategies in Go. Built for speed and reliability, Wisp handles market data ingestion, technical analysis, position management, and multi-exchange execution while you focus entirely on strategy logic.

What Makes Wisp Different​

Unlike traditional trading frameworks that require you to write polling loops or explicitly manage API calls, Wisp operates on a push-based, autonomous architecture:

  • Strategy-owned event loops — Your strategy runs in its own goroutine and controls execution timing
  • Asynchronous signal emission — Push signals via Emit() without blocking on exchange execution
  • Domain-scoped APIs — Separate contexts for Spot, Perpetuals, and Prediction markets
  • Real-time data streams — Automatic market data ingestion via batch backfill + WebSocket updates
  • Multi-exchange orchestration — Binance, Bybit, Hyperliquid, and more

How It Works: The Real Pattern​

Instead of implementing a method the framework calls repeatedly, you create your own execution loop:

type MomentumStrategy struct {
*strategy.BaseStrategy
wisp wisp.Wisp
}

// Your strategy owns its run loop
func (s *MomentumStrategy) Start(ctx context.Context) error {
return s.StartWithRunner(ctx, s.run) // Launch goroutine
}

// This runs in its own goroutine, controlled by you
func (s *MomentumStrategy) run(ctx context.Context) {
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()

for {
select {
case <-ctx.Done():
return // Clean shutdown
case <-ticker.C:
// YOUR STRATEGY LOGIC HERE
btcPair := s.wisp.Pair(
s.wisp.Asset("BTC"),
s.wisp.Asset("USDT"),
)

// Watch the pair (tells data ingestors to stream it)
s.wisp.Spot().WatchPair(connector.Binance, btcPair)

// Get live market data
price, ok := s.wisp.Spot().Price(connector.Binance, btcPair)
if !ok {
continue
}

// Check your signals and emit if triggered
if shouldBuy(price) {
signal := s.wisp.Spot().Signal(s.GetName()).
Buy(btcPair, connector.Binance, quantity, price).
Build()

s.Emit(signal) // Non-blocking push to executor
}

// Report status to monitoring
s.EmitStatus(strategy.StrategyStatus{
Summary: "BTC price: " + price.String(),
})
}
}
}

That's the real pattern. You own the loop. You control timing. You push signals.

What wisp Does for You​

Automatic Data Management​

// You write:
rsi, _ := s.k.Indicators().RSI(btc, 14)

// wisp handles:
// - Fetching price data from the exchange
// - Caching and managing historical data
// - Calculating the RSI indicator
// - Returning the current value

Exchange Abstraction​

// Same code works on any exchange
price, _ := s.k.Market().Price(btc) // Automatically uses your default exchange

// Or specify explicitly
price, _ := s.k.Market().Price(btc, indicators.IndicatorOptions{
Exchange: connector.Binance,
})

Built-in Indicators​

All technical indicators work the same way:

rsi, _ := s.k.Indicators().RSI(btc, 14)
sma, _ := s.k.Indicators().SMA(btc, 20)
ema, _ := s.k.Indicators().EMA(btc, 50)
macd, _ := s.k.Indicators().MACD(btc, 12, 26, 9)
bb, _ := s.k.Indicators().BollingerBands(btc, 20, 2.0)
stoch, _ := s.k.Indicators().Stochastic(btc, 14, 3)
atr, _ := s.k.Indicators().ATR(btc, 14)

Clean, consistent API. Pass the asset and parameters. wisp does the rest.

Market Data​

// Current price
price, _ := s.k.Market().Price(btc)

// Funding rates (for perpetuals)
funding, _ := s.k.Market().FundingRate(btc)

// Order book
book, _ := s.k.Market().OrderBook(btc)

// Prices across all exchanges
prices := s.k.Market().Prices(btc)

Cross-Exchange Operations​

// Find arbitrage opportunities
arbOpps := s.k.Market().FindArbitrage(btc, decimal.NewFromInt(10)) // 10 bps minimum

for _, opp := range arbOpps {
fmt.Printf("Buy on %s @ %s, Sell on %s @ %s\n",
opp.BuyExchange, opp.BuyPrice,
opp.SellExchange, opp.SellPrice)
}

A Complete Strategy​

Here's a full working strategy:

package main

import (
"github.com/wisp-trading/sdk/pkg/types/wisp"
"github.com/wisp-trading/sdk/pkg/types/strategy"
"github.com/shopspring/decimal"
)

type MomentumStrategy struct {
strategy.BaseStrategy
k wisp.wisp
}

func NewMomentum(k wisp.wisp) strategy.Strategy {
return &MomentumStrategy{k: k}
}

func (s *MomentumStrategy) GetSignals() ([]*strategy.Signal, error) {
btc := s.k.Asset("BTC")
eth := s.k.Asset("ETH")

// Get indicators (wisp fetches data automatically)
btcRSI, _ := s.k.Indicators().RSI(btc, 14)
ethRSI, _ := s.k.Indicators().RSI(eth, 14)

var signals []*strategy.Signal

// BTC oversold
if btcRSI.LessThan(decimal.NewFromInt(30)) {
signals = append(signals,
s.k.Signal(s.GetName()).
Buy(btc, connector.Binance, decimal.NewFromFloat(0.1)).
Build())
s.k.Log().Opportunity("Momentum", "BTC", "RSI oversold")
}

// ETH overbought
if ethRSI.GreaterThan(decimal.NewFromInt(70)) {
signals = append(signals,
s.k.Signal(s.GetName()).
Sell(eth, connector.Binance, decimal.NewFromFloat(1.0)).
Build())
s.k.Log().Opportunity("Momentum", "ETH", "RSI overbought")
}

return signals, nil
}

// Interface methods
func (s *MomentumStrategy) GetName() strategy.StrategyName {
return "Momentum"
}

func (s *MomentumStrategy) GetDescription() string {
return "RSI-based momentum strategy"
}

func (s *MomentumStrategy) GetRiskLevel() strategy.RiskLevel {
return strategy.RiskLevelMedium
}

func (s *MomentumStrategy) GetStrategyType() strategy.StrategyType {
return strategy.StrategyTypeTechnical
}

Key Features​

Type Safety​

Full compile-time checking with Go's type system:

// This won't compile - caught before runtime
rsi, _ := s.k.Indicators().RSI(btc, "14") // ❌ string instead of int

// This is correct
rsi, _ := s.k.Indicators().RSI(btc, 14) // ✅

Decimal Precision​

No floating-point errors:

import "github.com/shopspring/decimal"

// Financial-grade precision
price := decimal.NewFromFloat(50000.50)
quantity := decimal.NewFromFloat(0.1)
total := price.Mul(quantity) // Exact calculation

Write Once, Run Anywhere​

The same strategy code works in:

  • Backtesting - Test against historical data
  • Paper Trading - Practice with simulated funds
  • Live Trading - Deploy to real exchanges

No code changes. No environment checks. Just works.

Exchange Support​

Currently supported:

  • Binance
  • Bybit
  • Hyperliquid

Your strategy code doesn't care which exchange you use. wisp abstracts it all.

How It Works​

When you call an indicator or market data function, wisp:

  1. Identifies the data source - Uses your configured exchange or specified exchange
  2. Fetches required data - Gets price history, order book, funding rates, etc.
  3. Caches intelligently - Stores data to avoid redundant API calls
  4. Calculates/returns - Computes indicators or returns market data
  5. Handles errors - Manages rate limits, retries, and error cases

You just write s.k.Indicators().RSI(btc, 14) and wisp does the rest.

Multiple Timeframes​

Use different intervals for different purposes:

// Long-term trend (4-hour chart)
sma200, _ := s.k.Indicators().SMA(btc, 200, indicators.IndicatorOptions{
Interval: "4h",
})

// Short-term signal (1-hour chart)
rsi, _ := s.k.Indicators().RSI(btc, 14, indicators.IndicatorOptions{
Interval: "1h",
})

price, _ := s.k.Market().Price(btc)

// Only buy if:
// - Price is above 4h SMA200 (uptrend)
// - 1h RSI is oversold
if price.GreaterThan(sma200) && rsi.LessThan(decimal.NewFromInt(30)) {
signal := s.k.Signal(s.GetName()).
Buy(btc, connector.Binance, decimal.NewFromFloat(0.1)).
Build()
return []*strategy.Signal{signal}, nil
}

Multiple Assets​

Trade multiple assets in one strategy:

func (s *Strategy) GetSignals() ([]*strategy.Signal, error) {
btc := s.k.Asset("BTC")
eth := s.k.Asset("ETH")
sol := s.k.Asset("SOL")

var signals []*strategy.Signal

// Check each asset
for _, asset := range []portfolio.Asset{btc, eth, sol} {
rsi := s.k.Indicators().RSI(asset, 14)

if rsi.LessThan(decimal.NewFromInt(30)) {
signals = append(signals,
s.k.Signal(s.GetName()).
Buy(asset, connector.Binance, decimal.NewFromFloat(0.1)).
Build())
}
}

return signals, nil
}

Analytics​

Beyond indicators, wisp provides market analytics:

// Volatility analysis
vol, _ := s.k.Analytics().Volatility(btc, 24)

// Trend analysis
trend, _ := s.k.Analytics().Trend(btc, 50)
s.k.Log().Info("Trend: %s (Strength: %s%%)",
trend.Direction, trend.Strength)

// Volume analysis
volAnalysis, _ := s.k.Analytics().VolumeAnalysis(btc, 24)
if volAnalysis.IsVolumeSpike {
s.k.Log().MarketCondition("Volume spike detected")
}

// Price change
change, _ := s.k.Analytics().GetPriceChange(btc, 24)
s.k.Log().Info("24h change: %s%%", change.ChangePercent)

Architecture​

wisp consists of three components:

┌─────────────────────────────────────────────────────────┐
│ wisp-cli │
│ • Single CLI for all operations │
│ • Manages backtesting and live runtimes │
└──────────────────┬──────────────────────────────────────┘
│
┌─────────┴─────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ wisp-backtest │ │ wisp-live │
│ • Simulated │ │ • Real exchange │
│ exchange │ │ connectors │
│ • Historical │ │ • Live data │
│ data replay │ │ • Real orders │
└────────┬────────┘ └────────┬────────┘
│ │
└─────────┬──────────┘
│
▼
┌─────────────────────┐
│ wisp-sdk │
│ (this package) │
│ │
│ • Strategy API │
│ • Indicators │
│ • Market services │
└─────────────────────┘

As a strategy developer, you only interact with wisp-sdk. The CLI and runtimes are handled automatically.

Getting Started​

Ready to build your first strategy? Head to Getting Started.

API Reference​

Explore the complete API:

  • Indicators - Technical analysis indicators
  • Market Data - Prices, order books, funding rates
  • Analytics - Volatility, trend, volume analysis
  • Strategy Framework - Building and testing strategies

Philosophy​

wisp is built on these principles:

  1. Simplicity - Hide complexity, expose clean APIs
  2. Type Safety - Catch errors at compile time
  3. Precision - Use decimal arithmetic for financial calculations
  4. Write Once - Same code works everywhere
  5. Focus - You write strategy logic, we handle everything else

Community​

License​

wisp SDK is open source under the MIT License.