Range Bar in kdb

https://learninghub.kx.com/forums/topic/range-bar-in-kdb

Hi all,

I am a new kdb user, i'm trying step by step to transform backtest logic written in Python into q language. Specifically, I am encountering problems replicating logic for constant range bars (https://help.cqg.com/cqgic/19/default.htm#!Documents/rangebarrb.htm).

If I am not mistaken, conceptually, the scan logic should be used to replace a traditional for loop, but unfortunately, I cannot achieve the desired result.

Below, I share very rudimentary code that runs correctly but is actually very slow. Any suggestions to adapt this logic efficiently?

Thanks



// Constant range bars, the bars update each time the "high - low" target is reached

rangeBars:{[lastPrice; rangeTarget]

candle: enlist 1;

cumulativeRange: 0;

candleIdx: 1;

high: first lastPrice;

low: first lastPrice;

loopFn: {[params]

lastPrice: params 0;

rangeTarget: params 1;

cumulativeRange: params 2;

candleIdx: params 3;

high: params 4;

low: params 5;

candle: params 6;

index: params 7;

/ Update high & low

if[lastPrice[index] > high; cumulativeRange+: abs lastPrice[index] - high; high: lastPrice[index]];

if[lastPrice[index] < low; cumulativeRange+: abs lastPrice[index] - low; low: lastPrice[index]];

/ Trigger cond

triggerCond: cumulativeRange > rangeTarget;

/ Update Variables if trigger

if[triggerCond;

candleIdx+: 1;

cumulativeRange: 0;

high: lastPrice[index];

low: lastPrice[index];

];

candle,: candleIdx;

(lastPrice; rangeTarget; cumulativeRange; candleIdx; high; low; candle; index + 1)

};

/ Loop

params: (lastPrice; rangeTarget; cumulativeRange; candleIdx; high; low; candle; 0);

do[count lastPrice - 1; params: loopFn params];

:params 6;

};

lastPrice: 1.0500 1.0501 1.0502 1.0503 1.0504 1.0505 1.0506 1.0507 1.0508 1.0509 1.0510 1.0511 1.0512;

rangeTarget: 0.0003; / (3 pips)

rangeBars[lastPrice; rangeTarget]

Hi rgiu70,

not sure if this is what you are looking for, but if you have a table and just want to get the open, high, low, close by sym you can run the following query

q)t:([] sym:20?AAPLMSFTC; price:20?100.0)

q)t

sym price

-------------

MSFT 39.27524

MSFT 51.70911

C 51.59796

AAPL 40.66642

MSFT 17.80839

C 30.17723

MSFT 78.5033

C 53.47096

MSFT 71.11716

AAPL 41.1597

AAPL 49.31835

MSFT 57.85203

C 8.388858

MSFT 19.59907

C 37.5638

AAPL 61.37452

AAPL 52.94808

C 69.16099

AAPL 22.96615

MSFT 69.19531

q)exec ohlc!(first;max;min;last)@\:price by sym from t

| o h l c

----| -----------------------------------

AAPL| 40.66642 61.37452 22.96615 22.96615

C | 51.59796 69.16099 8.388858 69.16099

MSFT| 39.27524 78.5033 17.80839 69.19531

q)

`


@laura would you mind formatting my answer? thanks

Thank you for the response.

Specifically, I would like to create bars from a tick-by-tick dataset, where each bar has a specific range (for example, 10 pips). So, every time the max-min range is equal to 10, the "counter" should reset and start counting max-min again. Every time the range is greater than 10, a new OHLC bar is generated.

This is a specific example for this type of bars (range bar chart):



So it is necessary to:

  1. Map the cumulative (high - low)
  2. If the cumulative (high - low) is greater than the set range, then a new bar is generated, independent of time
  3. When a new bar is generated, the high - low "counter" must reset and start from 0

Unfortunately, I can't recreate this logic with scan. In the example I shared, it is very rudimentary but it works. That is, every time the range exceeds the set value, an index number is incremented by 1 (new bar index).

It seems to me, you need to break when the range is met.


f:{1+1_first -2#{x,last where z=abs y[last x] - y}[;x;y]\ [{0<=last deltas -2#x};0]}

where (1+til count c)!c:deltas f[lastPrice;rangeTarget]

1 1 1 1 2 2 2 3 3 3 4 4 4