/ Exchanges / src / _orderbook.jl
_orderbook.jl
 1  @doc "Utilities for orderbook based strategies."
 2  
 3  using StatsBase: iqr
 4  
 5  function mon_obi(exc, pair, runs=60 * 5)
 6      imbs = Array{Real}(undef, runs)
 7      price = similar(imbs)
 8      r = 1
 9      while r < runs + 1
10          imbs[r], price[r] = obimbalance(exc, pair; use_last=true)
11          sleep(1)
12          r += 1
13      end
14      imbs, price
15  end
16  
17  macro fetchob(args...)
18      ob = esc(:ob)
19      exc = esc(:exc)
20      pair = esc(:pair)
21      quote
22          if isnothing($ob)
23              $ob = $exc.fetchOrderBook($pair)
24          end
25      end
26  end
27  
28  @doc "Aggregates orderbook prices based on volume."
29  function vwap(data, stepvalue; price_vol=true, bid_ask=true, dosort=true)
30      by = price_vol ? :price : :volume
31      div_sym = price_vol ? :price_div : :volume_div
32      if isnothing(stepvalue)
33          stepvalue = iqr(data[:, by])
34      end
35      # the range label
36      data[:, div_sym] = div.(data[:, by], stepvalue)
37      # the volume in quote currency
38      data[:, :q_volume] = data[:, :price] .* data[:, :volume]
39      # group by ranges
40      gd = groupby(data, div_sym)
41      # apply/combine
42      groups = combine(gd, [:q_volume => sum, :volume => sum])
43      groups[:, :vwap] = groups[:, :q_volume_sum] ./ groups[:, :volume_sum]
44      dosort ? sort(groups, :vwap; rev=bid_ask) : groups
45  end
46  
47  @doc "The orderbook imbalance function. [(bids_price - ask_price) / (bids_price + ask_price)]"
48  function obimbalance(exc, pair; ob=nothing, level=nothing, use_last=false)
49      @fetchob
50      if isnothing(level) && use_last
51          ticker = exc.fetchTicker(pair)
52          level = ticker["last"]
53      end
54      aob = orderbook(exc, pair; ob, stepvalue=level)
55      bvs = aob.bids[1, :vwap]
56      avs = aob.asks[1, :vwap]
57      ((bvs - avs) / (bvs + avs), level)
58  end
59  
60  @doc """
61  - `by` key by which to aggregate values (:price or :volume)
62  - `stepvalue` size of the bins for aggregation (the range value of :price or :volume). If it is nothing,
63  it takes the average of the first 10 elements of the array.
64  """
65  function orderbook(exc, pair; ob=nothing, stepvalue::Union{Nothing,Real}=nothing, by=:price)
66      @fetchob
67      bids = DataFrame(ob["bids"], ["price", "volume"])
68      asks = DataFrame(ob["asks"], ["price", "volume"])
69      price_vol = by === :price
70      (
71          ob=ob,
72          bids=vwap(bids, stepvalue; price_vol, bid_ask=true),
73          asks=vwap(asks, stepvalue; price_vol, bid_ask=false),
74      )
75  end