KX Community

Find answers, ask questions, and connect with our KX Community around the world.
KX Community Guidelines

Home Forums kdb+ Range Bar in kdb

  • Range Bar in kdb

    Posted by rgiu70 on July 23, 2024 at 2:36 pm

    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]

    sujoy replied 3 months, 4 weeks ago 3 Members · 6 Replies
  • 6 Replies
  • unterrainer_ale

    Member
    July 23, 2024 at 3:52 pm

    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

    </p><p>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)

    `

  • unterrainer_ale

    Member
    July 23, 2024 at 3:53 pm

    @laura would you mind formatting my answer? thanks

  • rgiu70

    Member
    July 23, 2024 at 4:13 pm

    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.

  • rgiu70

    Member
    July 23, 2024 at 4:17 pm

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

  • rgiu70

    Member
    July 23, 2024 at 4:24 pm

    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).

  • sujoy

    Member
    July 27, 2024 at 6:25 am

    <div>It seems to me, you need to break when the range is met.</div>

    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

Log in to reply.