TA-Lib / ta-lib-python

Python wrapper for TA-Lib (http://ta-lib.org/).
http://ta-lib.github.io/ta-lib-python
Other
9.46k stars 1.74k forks source link

Calculation Error? #516

Open paris0120 opened 2 years ago

paris0120 commented 2 years ago

I'm developing a similar library and testing the results with this lib (https://github.com/paris0120/talibjs.git ). I find that there might be some calculation errors. I compare the results with the python version and look into the algorithm in Java. For example ADX, line 524 525:

                                                prevMinusDM /= (double)optInTimePeriod;
                                                prevPlusDM /= (double)optInTimePeriod;

I believe that they should be

                                                prevMinusDM -=prevMinusDM /(double)optInTimePeriod;
                                                prevPlusDM -= prevPlusDM /(double)optInTimePeriod;

I also got different results with ATR. However, both the trueRange and SMA function work correctly but the ATR doesn't have the correct number. (I calculated manually to verify that my version has the correct number).

trufanov-nok commented 2 years ago

Could you provide a direct links to the code lines you are comparing?

paris0120 commented 2 years ago

I don't think that it's publicly available. All the functions are in the core.class.

trufanov-nok commented 2 years ago

This is ADX code from TA-Lib C library, which is under the hood of this python wrapper:
https://github.com/TA-Lib/ta-lib/blob/master/src/ta_func/ta_ADX.c#L414 It contains:

      prevMinusDM -= prevMinusDM/optInTimePeriod;
      prevPlusDM  -= prevPlusDM/optInTimePeriod;

All the functions are in the core.class.

Where I can find that core.class file?

paris0120 commented 2 years ago

I have no idea where it goes wrong but here is my worksheet. The results with talib for dx is array([ nan, nan, nan, nan, 100. , 58.70967742, 55.64929196, 71.1993739 , 71.1993739 , 26.23631438]) <html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">

h | 146.59 | 145.74 | 145.7 | 145.47 | 145.12 | 145.26 | 145.27 | 145.25 | 145.01 | 145.13 -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- l | 145.85 | 145.53 | 145.4 | 145 | 144.92 | 145 | 145.12 | 144.91 | 144.92 | 144.93 c | 146.2 | 145.58 | 145.47 | 145.12 | 145.03 | 145.11 | 145.25 | 144.98 | 144.98 | 145.1 tr | nan | 0.67 | 0.3 | 0.47 | 0.2 | 0.26 | 0.16 | 0.34 | 0.09 | 0.2 trsum |   |   |   |   | 581.2 | 581.01 | 581.0075 | 580.7356 | 580.5317 | 580.4988 atr |   |   |   |   | 145.3 | 145.2525 | 145.2519 | 145.1839 | 145.1329 | 145.1247 up |   | -0.85 | -0.04 | -0.23 | -0.35 | 0.14 | 0.01 | -0.02 | -0.24 | 0.12 down |   | 0.32 | 0.13 | 0.4 | 0.08 | -0.08 | -0.12 | 0.21 | -0.01 | -0.01 pdm |   | 0 | 0 | 0 | 0 | 0.14 | 0.01 | 0 | 0 | 0.12 ndm |   | 0.32 | 0.13 | 0.4 | 0.08 | 0 | 0 | 0.21 | 0 | 0 psum |   |   |   |   | 0 | 0.14 | 0.115 | 0.08625 | 0.064688 | 0.168516 nsum |   |   |   |   | 0.93 | 0.6975 | 0.523125 | 0.602344 | 0.451758 | 0.338818 pdi |   |   |   |   | 0 | 0.000241 | 0.000198 | 0.000149 | 0.000111 | 0.00029 ndi |   |   |   |   | 0.0016 | 0.0012 | 0.0009 | 0.001037 | 0.000778 | 0.000584 dx |   |   |   |   | 100 | 66.56716 | 63.9569 | 74.94894 | 74.94894 | 33.56817

paris0120 commented 2 years ago

test script with python

h = np.array([146.59,145.74,145.7,145.47,145.12,145.26,145.27,145.25,145.01,145.13]); l = np.array([145.85,145.53,145.4,145.0,144.92,145.0,145.12,144.91,144.92,144.93]); c = np.array([146.2,145.58,145.47,145.12,145.03,145.11,145.25,144.98,144.98,145.1]); talib.ADX(h, l, c, 4)

trufanov-nok commented 2 years ago

I'm running:

import talib import numpy as np h = np.array([146.59,145.74,145.7,145.47,145.12,145.26,145.27,145.25,145.01,145.13]); l = np.array([145.85,145.53,145.4,145.0,144.92,145.0,145.12,144.91,144.92,144.93]); c = np.array([146.2,145.58,145.47,145.12,145.03,145.11,145.25,144.98,144.98,145.1]); talib.ADX(h, l, c, timeperiod=4)

And getting

array([        nan,         nan,         nan,         nan,         nan,
               nan,         nan, 71.38958582, 71.34203284, 60.06560322])

Could you recheck your results?

paris0120 commented 2 years ago

I tracked back to DX. I can't go further because there is no function for DM and DI. The results above is for DX. For ADX it should be [null, null, null, null, null, null, null, 76.36825350866403, 76.01342634661, 65.40211226154518]

paris0120 commented 2 years ago

Here is the working sheet:

<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">

h | 146.59 | 145.74 | 145.7 | 145.47 | 145.12 | 145.26 | 145.27 | 145.25 | 145.01 | 145.13 -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- l | 145.85 | 145.53 | 145.4 | 145 | 144.92 | 145 | 145.12 | 144.91 | 144.92 | 144.93 c | 146.2 | 145.58 | 145.47 | 145.12 | 145.03 | 145.11 | 145.25 | 144.98 | 144.98 | 145.1 tr | nan | 0.67 | 0.3 | 0.47 | 0.2 | 0.26 | 0.16 | 0.34 | 0.09 | 0.2 trsum |   |   |   |   | 581.2 | 581.01 | 581.0075 | 580.7356 | 580.5317 | 580.4988 atr |   |   |   |   | 145.3 | 145.2525 | 145.2519 | 145.1839 | 145.1329 | 145.1247 up |   | -0.85 | -0.04 | -0.23 | -0.35 | 0.14 | 0.01 | -0.02 | -0.24 | 0.12 down |   | 0.32 | 0.13 | 0.4 | 0.08 | -0.08 | -0.12 | 0.21 | -0.01 | -0.01 pdm |   | 0 | 0 | 0 | 0 | 0.14 | 0.01 | 0 | 0 | 0.12 ndm |   | 0.32 | 0.13 | 0.4 | 0.08 | 0 | 0 | 0.21 | 0 | 0 psum |   |   |   |   | 0 | 0.14 | 0.115 | 0.08625 | 0.064688 | 0.168516 nsum |   |   |   |   | 0.93 | 0.6975 | 0.523125 | 0.602344 | 0.451758 | 0.338818 pdi |   |   |   |   | 0 | 0.000241 | 0.000198 | 0.000149 | 0.000111 | 0.00029 ndi |   |   |   |   | 0.0016 | 0.0012 | 0.0009 | 0.001037 | 0.000778 | 0.000584 dx |   |   |   |   | 100 | 66.56716 | 63.9569 | 74.94894 | 74.94894 | 33.56817 sum |   |   |   |   |   |   |   | 305.473 | 304.0537 | 261.6084 adx |   |   |   |   |   |   |   | 76.36825 | 76.01343 | 65.40211

trufanov-nok commented 2 years ago

Ок, so we discussing DX. Could you show how your DX is calculated?

paris0120 commented 2 years ago

I track the issue to dx. dx to adx is correct.

Here is my code. The results are consistent with the ones from the worksheet above. https://github.com/paris0120/talib.ts/blob/dev/src/index.ts#L433

paris0120 commented 2 years ago

I don't apply abs there coz I don't think that it makes sense, so the result there will be negative.

trufanov-nok commented 2 years ago

I don't know Typescript.... Could you veify your tRange()?
The TA-Lib's implementation (particularly used in DX) is:

   #define TRUE_RANGE(TH,TL,YC,OUT) {\
      OUT = TH-TL; \
      tempReal2 = std_fabs(TH-YC); \
      if( tempReal2 > OUT ) \
         OUT = tempReal2; \
      tempReal2 = std_fabs(TL-YC); \
      if( tempReal2 > OUT ) \
         OUT = tempReal2; \
   }

Note the std_fabs.
Your is tRange: h.subtract(l).max(h.distance(c)).max(l.distance(c)). I guess without abs it should return wrong value.

paris0120 commented 2 years ago

trange works fine. I have the same result as talib. > I don't know Typescript.... Could you veify your tRange()?

The TA-Lib's implementation (particularly used in DX) is:


   #define TRUE_RANGE(TH,TL,YC,OUT) {\

      OUT = TH-TL; \

      tempReal2 = std_fabs(TH-YC); \

      if( tempReal2 > OUT ) \

         OUT = tempReal2; \

      tempReal2 = std_fabs(TL-YC); \

      if( tempReal2 > OUT ) \

         OUT = tempReal2; \

   }

Note the std_fabs.

Your is tRange: h.subtract(l).max(h.distance(c)).max(l.distance(c)). I guess without abs it should return wrong value.

trufanov-nok commented 2 years ago

I've successfully installed talibjs with: npm install talib.ts@latest --S But then

$ nodejs 
Welcome to Node.js v12.22.9.
Type ".help" for more information.
> import { TALib } from 'talibjs';
import { TALib } from 'talibjs';
^^^^^^

Uncaught:
SyntaxError: Cannot use import statement inside the Node.js repl, alternatively use dynamic import

How can I set up a working example to reproduce a problem?

paris0120 commented 2 years ago

this is a library. Download my repository. run

  1. npm install
  2. npm run test

you can find the test script in test/test.ts. you can add this for tRange test

    expect(TALib.tRange(high, low, close).tRange.getValue()).toEqual([null, 0.6699999999999875, 0.29999999999998295, 0.46999999999999886, 0.20000000000001705, 0.2599999999999909, 0.1599999999999966, 0.3400000000000034, 0.09000000000000341, 0.19999999999998863,]);
trufanov-nok commented 2 years ago

I also got different results with ATR. However, both the trueRange and SMA function work correctly but the ATR doesn't have the correct number. (I calculated manually to verify that my version has the correct number).

Let's discuss ATR. SMA there is used only to calculate very first value (which is just average) then another smoothing is applied:

After that, Wilder sought to smooth the data by incorporating the previous period's ATR value.

Current ATR = [(Prior ATR x 13) + Current TR] / 14

  • Multiply the previous 14-day ATR by 13.
  • Add the most recent day's TR value.
  • Divide the total by 14

https://school.stockcharts.com/doku.php?id=technical_indicators:average_true_range_atr

In TA-Lib this smoothing looks like:

   while( --nbATR != 0 )
   {
      prevATR *= optInTimePeriod - 1;
      prevATR += tempBuffer[today++];
      prevATR /= optInTimePeriod;
      outReal[outIdx++] = prevATR;
   }

The code is here: https://github.com/TA-Lib/ta-lib/blob/master/src/ta_func/ta_ATR.c#L281

This smoothing looks very similar to your modifiedMovingAverage. I also noticed in di(): let atr =this.tRange(high, low, close).tRange.modifiedMovingAverage(period); Which is differs from your regular atr calculation.

But I suspect that modifiedMovingAverage may be not exactly the same smoothing as in TA'Lib.
Bcs in TA-Lib:

nextATR = (prevATR*(period-1) + value) / period = prevATR - prevATR/period + value / period =
prevATR - (prevATR + value) / period

In your modifiedMovingAverage the loop is

sum += this.value[i];
                if (c >= period) {
                    output.push(sum / period);
                    sum -= sum / period;
                }

i'm not sure if they are equal. Could you doublecheck?

paris0120 commented 2 years ago

ATR is calculated with SMA. DI is calculated with modified ma as you suggested

https://github.com/paris0120/talib.ts/blob/dev/src/index.ts#L412

trufanov-nok commented 2 years ago

ATR is calculated with SMA

Why it's calculated with SMA?

paris0120 commented 2 years ago

I follow the method here.

https://www.investopedia.com/terms/a/atr.asp

However, how I calculate ATR doesn't affect ADX because ADX is calculated with modified MA instead of SMA as I showed you above.

trufanov-nok commented 2 years ago

ADX is calculated with modified MA instead of SMA as I showed you above. And I said I suspect your modified MA is wrong too, but didn't compared them in details yet.

I follow the method here. https://www.investopedia.com/terms/a/atr.asp

In this case I could say that TA-Lib's ATR calculation is based on approach of its inventor, which is described in wiki: https://en.wikipedia.org/wiki/Average_true_range
Also I noticed that investopedia's article is controversial. There is a paragraph:

Example of How to Use the Average True Range (ATR) As a hypothetical example, assume the first value of the five-day ATR is calculated at 1.41 and the sixth day has a true range of 1.09. The sequential ATR value could be estimated by multiplying the previous value of the ATR by the number of days less one, and then adding the true range for the current period to the product.

Next, divide the sum by the selected timeframe. For example, the second value of the ATR is estimated to be 1.35, or (1.41 * (5 - 1) + (1.09)) / 5. The formula could then be repeated over the entire time period.

That's look like a TA-Lib's approach. Probably the article is misleading.

paris0120 commented 2 years ago

OK I will change the ATR calculation but here the ADX function doesn't depend on ATR function. the ATR used in ADX is calculated separately with modified MA.

Or forget my library and just force on the test case I provided above. The worksheet shows my calculation with MMA.

trufanov-nok commented 2 years ago

You will change the ATR calculation, and it will not match the TA-Lib's resultrs anyway, bcs your MMA might be wrong. That's what I would expect. Let's fix ATR, and will see if ADX still incorrect. Just change ATR and test it across TA-Lib

paris0120 commented 2 years ago

It's changed but this will not affect adx calculation. As I said, ADX is calculated seperately.

trufanov-nok commented 2 years ago

does atr results match ta-lib's atr now?

paris0120 commented 2 years ago

I currently don't have the python lib now. I guess the results should match now for ATR. However, this won't change the results for ADX. As I showed you above, I verified the results manually. The difference is not caused by atr.

trufanov-nok commented 2 years ago

I currently don't have the python lib now. I guess the results should match now for ATR.

No, they are still wrong:

import {TALib} from "../index";

describe('testing index file', () => {
    let open = [146.28,145.7,145.47,145.47,145.12,145.02,145.25,145.19,144.97,144.95];
    let high = [146.59,145.74,145.7,145.47,145.12,145.26,145.27,145.25,145.01,145.13];
    let low = [145.85,145.53,145.4,145.0,144.92,145.0,145.12,144.91,144.92,144.93];
    let close = [146.2,145.58,145.47,145.12,145.03,145.11,145.25,144.98,144.98,145.1];
    let volume = [9294955,1013555,1010936,1036917,841699,947339,771789,1480890,1308324,967320];
    test('+ - * / % ^', () => {
        expect(TALib.atr(high, low, close, 4).atr.getValue()).toEqual([       null,        null,        null,        null, 0.41      ,       0.3725    , 0.319375  , 0.32453125, 0.26589844, 0.24942383]);
    });

});
 ● testing index file › + - * / % ^

    expect(received).toEqual(expected) // deep equality

    - Expected  - 6
    + Received  + 6

      Array [
        null,
        null,
        null,
        null,
    -   0.41,
    -   0.3725,
    -   0.319375,
    -   0.32453125,
    -   0.26589844,
    -   0.24942383,
    +   0.4099999999999966,
    +   0.30749999999999744,
    +   0.27250000000000085,
    +   0.240000000000002,
    +   0.21249999999999858,
    +   0.197499999999998,
      ]

In python:

import talib
import numpy as np

h = np.array([146.59,145.74,145.7,145.47,145.12,145.26,145.27,145.25,145.01,145.13]);
l = np.array([145.85,145.53,145.4,145.0,144.92,145.0,145.12,144.91,144.92,144.93]);
c = np.array([146.2,145.58,145.47,145.12,145.03,145.11,145.25,144.98,144.98,145.1]);
talib.ATR(h, l, c, timeperiod=4)

array([       nan,        nan,        nan,        nan, 0.41      ,
       0.3725    , 0.319375  , 0.32453125, 0.26589844, 0.24942383])

>>>
paris0120 commented 2 years ago

Sorry I forgot to compile the package. It's now working.

    expect(TALib.atr(high, low, close, 4).atr.toFixed(5).getValue()).toEqual([null, null, null, null, 0.41,  0.3725, 0.31937, 0.32453, 0.2659, 0.24942]);
trufanov-nok commented 2 years ago

Ok, I can confirm that ATR is fixed now. Well, I need to check adx...

trufanov-nok commented 2 years ago

I'm looking at DM calculation here: https://github.com/paris0120/talib.ts/blob/dev/src/index.ts#L396

it seems it conditionally multiplies pdm and ndm. But I believe it should conditionally sum them instead. Could you doeublecheck?

paris0120 commented 2 years ago

Up and down are calculated first. Then if they meet the conditions they are the pdm or ndm otherwise 0.

It's equivalent to https://github.com/TA-Lib/ta-lib/blob/master/src/ta_func/ta_ADX.c#L465 . In your case, you don't add the value and I add the value as 0.

trufanov-nok commented 2 years ago

I'm not getting the typescript code then:

        let up = h.subtract(h.lag(1));
        let down = l.lag(1).subtract(l);

This seems to be up[i] = h[i] - h[i-1] and down[i] = l[i-1] - l[i]. OK. Then we have:

 pdm: up.greaterThan(down).and(up.greaterThan(0)).multiply(up),
 ndm: down.greaterThan(up).and(down.greaterThan(0)).multiply(down)

which looks for me like

if (up[i] > down[i]) and (up[i] > 0) then
pdm[i] = ???

if up.greaterThan(down).and(up.greaterThan(0)) is 0 or 1 then multiply have sense. In this case

pdm[i] = up[i] or 0

which is wrong. As pdm should be a commulative sum, like in TA-Lib's: https://github.com/TA-Lib/ta-lib/blob/master/src/ta_func/ta_ADX.c#L473

pdim[i] = pdm[i-1] + (up[i] or 0)

mrjbq7 commented 2 years ago

I don't mind at all using this issue for this kind of debugging, but are we wondering if TA-Lib has a bug, or are we trying to figure out why this typescript implementation is buggy?

paris0120 commented 2 years ago

I cumulate DM in the DI calculation (https://github.com/paris0120/talib.ts/blob/dev/src/index.ts#L416) as the Smoothed DM as defined here https://www.investopedia.com/terms/a/adx.asp#:~:text=To%20get%20the%20ADX%2C%20continue,%2B%20current%20DX)%20%2F%2014.

paris0120 commented 2 years ago

I don't mind at all using this issue for this kind of debugging, but are we wondering if TA-Lib has a bug, or are we trying to figure out why this typescript implementation is buggy?

I currently believe that TA-Lib has a bug. Both the results of the worksheet and from my library don't match the results from the TA-Lib.

trufanov-nok commented 2 years ago

@mrjbq7

are we wondering if TA-Lib has a bug, or are we trying to figure out why this typescript implementation is buggy?

We don't know yet.

As pdm should be a commulative sum, like in TA-Lib's:

Ok, I was wrong here as it's hard to read the old C code - it's optimized for speed and do all calcs in a few loops. Looks like this sum is a part of further smoothing.

I've debugged C code a bit and found out at least one discrepancy. The TR is same in C and typescript but when C uses its smoothed value - it's different. For ex: console.log(TALib.tRange(high, low, close).tRange.modifiedMovingAverage(4).getValue());
is

    [
      null,
      null,
      null,
      null,
      0.4099999999999966,
      0.37249999999999517,
      0.3193749999999955,
      0.3245312499999975,
      0.265898437499999,
      0.2494238281249964
    ]

While TA-Libs results will be: null, null, null, 1.280000, 1.220000, 1.075000, 1.146250, 0.949687, 0.912266.
They differ from very first non null value.
Non smoothed TR values are:

    [
      null,
      0.6699999999999875,
      0.29999999999998295,
      0.46999999999999886,
      0.20000000000001705,
      0.2599999999999909,
      0.1599999999999966,
      0.3400000000000034,
      0.09000000000000341,
      0.19999999999998863
    ]

The typescript calculates very first value as:

(0.6699999999999875 + 0.29999999999998295 + 0.46999999999999886 + 0.20000000000001705) / 4 = 0.41

which is just an SMA.

TA-Libs first value calculated as

 sum = (0.6699999999999875 +  0.29999999999998295 + 0.46999999999999886); // 1.44
  val = sum - sum/4 + 0.20000000000001705 = 1.28

So unlike ATR in ADX TA-Lib smoothes the TR values differently. First smoothed value isn't SMA, it callculates all values with the Wilder's smoothing approach from very beginning. Let's check the investopedia description:

  1. First 14TR = sum of first 14 TR readings.
  2. Next 14TR value = first 14TR - (prior 14TR/14) + current TR.

Not clear enouth but nothing about SMA or averaging the first value.

So it seems you can't use modifiedMovingAverage from ATR in ADX at least for TR, but I would check other smoothed vals too.

trufanov-nok commented 2 years ago

TA-Lib is older than Investopedia. It's better to refer to the Wilder's book as a source: https://media.indianpdf.com/visitors-uploaded/New-Concepts-In-Technical-Trading-Systems-J.-Welles-Wilfer-Jr-Read-Book-www.indianpdf.com_-Download-Online-Free.pdf The page 37 describes TR smoothing in ADX.

paris0120 commented 2 years ago

TA-Lib is older than Investopedia. It's better to refer to the Wilder's book as a source: https://media.indianpdf.com/visitors-uploaded/New-Concepts-In-Technical-Trading-Systems-J.-Welles-Wilfer-Jr-Read-Book-www.indianpdf.com_-Download-Online-Free.pdf The page 37 describes TR smoothing in ADX.

Yes I did in DI https://github.com/paris0120/talib.ts/blob/dev/src/index.ts#L416

paris0120 commented 2 years ago

TA-Lib is older than Investopedia. It's better to refer to the Wilder's book as a source: https://media.indianpdf.com/visitors-uploaded/New-Concepts-In-Technical-Trading-Systems-J.-Welles-Wilfer-Jr-Read-Book-www.indianpdf.com_-Download-Online-Free.pdf The page 37 describes TR smoothing in ADX.

Let's focus on TA-Lib instead of my lib. Calculate ADX manually and verify the results.

trufanov-nok commented 2 years ago

ADX in TA-Lib and in your lib are calculated differently. I explained you this difference. The question is: which of them calculate ADX correctly? It seems for me that TA-Lib's approach is the correct one as your approach doesn't mach neither Investopedia nor the book.

paris0120 commented 2 years ago

I have the smooth in the DI function. It matches the definition.

trufanov-nok commented 2 years ago

It doesn't match definition. You smoothment is: https://github.com/paris0120/numbers.ts/blob/0efc01709046a74c29391c86944f32d9918ac83c/src/index.ts#L612

sum += this.value[i];
                if (c >= period) {
                    output.push(sum/period);
                    sum -= sum / period;
                }

Which means when c == period the output is averaged sum. That's correct for ATR: https://en.wikipedia.org/wiki/Average_true_range

The first ATR value is calculated using the arithmetic mean formula:

And this matches ATR implementation in TA-Lib.

But nothing like that is described for TR in ADX. The investopedia and the book says nothing about averaging first smoothed value. At least I don't see it. May you find something? And TA-Lib's implementation doesn't average the first value. I've explained how it calculates the first value. That means TA-Lib uses different smoothing in ATR and for TR used in ADX. And it looks like this is aligned with the docs.

paris0120 commented 2 years ago

It doesn't match definition. You smoothment is: https://github.com/paris0120/numbers.ts/blob/0efc01709046a74c29391c86944f32d9918ac83c/src/index.ts#L612

sum += this.value[i];
                if (c >= period) {
                    output.push(sum/period);
                    sum -= sum / period;
                }

Which means when c == period the output is averaged sum. That's correct for ATR: https://en.wikipedia.org/wiki/Average_true_range

The first ATR value is calculated using the arithmetic mean formula:

And this matches ATR implementation in TA-Lib.

But nothing like that is described for TR in ADX. The investopedia and the book says nothing about averaging first smoothed value. At least I don't see it. May you find something? And TA-Lib's implementation doesn't average the first value. I've explained how it calculates the first value. That means TA-Lib uses different smoothing in ATR and for TR used in ADX. And it looks like this is aligned with the docs.

TA-Lib does the same https://github.com/TA-Lib/ta-lib/blob/master/src/ta_func/ta_ADX.c#L386

trufanov-nok commented 2 years ago

Not the same. TA-Lib's first prevTR at https://github.com/TA-Lib/ta-lib/blob/master/src/ta_func/ta_ADX.c#L484 is (0.6699999999999875 + 0.29999999999998295 + 0.46999999999999886) - (0.6699999999999875 + 0.29999999999998295 + 0.46999999999999886)/4 + 0.20000000000001705 = 1.28 and yours (0.6699999999999875 + 0.29999999999998295 + 0.46999999999999886 + 0.20000000000001705) / 4 = 0.41

paris0120 commented 2 years ago

Not the same. TA-Lib's first prevTR at https://github.com/TA-Lib/ta-lib/blob/master/src/ta_func/ta_ADX.c#L484 is (0.6699999999999875 + 0.29999999999998295 + 0.46999999999999886) - (0.6699999999999875 + 0.29999999999998295 + 0.46999999999999886)/4 + 0.20000000000001705 = 1.28 and yours (0.6699999999999875 + 0.29999999999998295 + 0.46999999999999886 + 0.20000000000001705) / 4 = 0.41

I guess that's the difference. I can't see the meaning of dividing the sum of 3 numbers by 4. You can call it a feature but personally I feel that it's a bug.

mrjbq7 commented 2 years ago

Does TA-Lib match other libraries, besides yours?

paris0120 commented 2 years ago

Does TA-Lib match other libraries, besides yours?

Sadly, all the libraries I found are based on TA-Lib. That's why I'm rewriting one.

trufanov-nok commented 2 years ago

There is an example table of ADX calculation step by step in WIlder's book at page 42.
https://media.indianpdf.com/visitors-uploaded/New-Concepts-In-Technical-Trading-Systems-J.-Welles-Wilfer-Jr-Read-Book-www.indianpdf.com_-Download-Online-Free.pdf

The column 6 is current TR, Column 9 is smoothed TR(14 period). First TR14 value is at day 15 and it's: 43.32. And it looks like it's

sum = 3 + 2.25 + 2.75 + 1 + 2.50 + 3.50 + 3.50 + 4.25 + 3.50 + 6.50 +2.25 + 2 + 4 = 41
tr14 = 41 - 41/14 + 5.25 = 43.32

Note that there are 13 values in sum, bcs TR1 cant be calculated at day 1.
I guess TA-Lib authors copied this approach from his book and Wilder is inventor of ADX if I recall right.

P.S. There is a "Totals" row before day 15 which seems to be just for the info and it contains sums of previous raws for some columns. Due to a bad authors calligraphy I read 44 instead of 41 for column 6. But it's 41 - I even recalculated the column to ensure.

paris0120 commented 2 years ago

1 + 2.50 + 3.50

Really appreciate the effort. I really don't see how this works. The mean is first underestimated and then takes a long period to regress to an unbiased mean. I guess Wilder didn't know much about math.