1 /* TA-LIB Copyright (c) 1999-2007, Mario Fortier
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in
13  *   the documentation and/or other materials provided with the
14  *   distribution.
15  *
16  * - Neither name of author nor the names of its contributors
17  *   may be used to endorse or promote products derived from this
18  *   software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /* List of contributors:
35  *
36  *  Initial  Name/description
37  *  -------------------------------------------------------------------
38  *  MF       Mario Fortier
39  *
40  *
41  * Change history:
42  *
43  *  MMDDYY BY   Description
44  *  -------------------------------------------------------------------
45  *  112400 MF   First version.
46  *
47  */
48 
49 /* Description:
50  *     Regression test of MACD.
51  */
52 
53 /**** Headers ****/
54 #include <stdio.h>
55 #include <string.h>
56 
57 #include "ta_test_priv.h"
58 #include "ta_test_func.h"
59 #include "ta_utility.h"
60 #include "ta_memory.h"
61 
62 /**** External functions declarations. ****/
63 /* None */
64 
65 /**** External variables declarations. ****/
66 /* None */
67 
68 /**** Global variables definitions.    ****/
69 /* None */
70 
71 /**** Local declarations.              ****/
72 typedef enum {
73 TA_MACD_TEST,
74 TA_MACDFIX_TEST,
75 TA_MACDEXT_TEST
76 } TA_TestId;
77 
78 typedef struct
79 {
80    TA_Integer doRangeTestFlag;
81    TA_TestId  testId;
82 
83    TA_Integer startIdx;
84    TA_Integer endIdx;
85 
86    TA_Integer optInFastPeriod;
87    TA_Integer optInSlowPeriod;
88    TA_Integer optInSignalPeriod_2;
89    TA_Integer compatibility;
90 
91    TA_RetCode expectedRetCode;
92 
93    TA_Integer expectedBegIdx;
94    TA_Integer expectedNbElement;
95 
96    TA_Integer oneOfTheExpectedOutRealIndex0;
97    TA_Real    oneOfTheExpectedOutReal0;
98 
99    TA_Integer oneOfTheExpectedOutRealIndex1;
100    TA_Real    oneOfTheExpectedOutReal1;
101 
102    TA_Integer oneOfTheExpectedOutRealIndex2;
103    TA_Real    oneOfTheExpectedOutReal2;
104 
105 } TA_Test;
106 
107 typedef struct
108 {
109    const TA_Test *test;
110    const TA_Real *close;
111 } TA_RangeTestParam;
112 
113 /**** Local functions declarations.    ****/
114 static ErrorNumber do_test( const TA_History *history,
115                             const TA_Test *test );
116 
117 /**** Local variables definitions.     ****/
118 static TA_Test tableTest[] =
119 {
120 
121    /*********************/
122    /*   MACD - CLASSIC  */
123    /*********************/
124    { 0, TA_MACD_TEST, 0, 251, 12, 26, 9, TA_COMPATIBILITY_DEFAULT, TA_SUCCESS,  33, 252-33, /* 25, 252-25,*/
125                                                           0, -1.9738,  /* MACD */
126                                                           0, -2.7071,  /* Signal */
127                                                           0, (-1.9738)-(-2.7071) }, /* Histogram */
128 
129    /* Test period inversion */
130    { 0, TA_MACD_TEST, 0, 251, 26, 12, 9, TA_COMPATIBILITY_DEFAULT, TA_SUCCESS,  33, 252-33, /* 25, 252-25,*/
131                                                           0, -1.9738,  /* MACD */
132                                                           0, -2.7071,  /* Signal */
133                                                           0, (-1.9738)-(-2.7071) }, /* Histogram */
134 
135    /***********************/
136    /*   MACD - METASTOCK  */
137    /***********************/
138 
139    /*******************************/
140    /*   MACDEXT - MIMIC CLASSIC   */
141    /*******************************/
142    { 0, TA_MACDEXT_TEST, 0, 251, 12, 26, 9, TA_COMPATIBILITY_DEFAULT, TA_SUCCESS,  33, 252-33, /* 25, 252-25,*/
143                                                           0, -1.9738,  /* MACD */
144                                                           0, -2.7071,  /* Signal */
145                                                           0, (-1.9738)-(-2.7071)}, /* Histogram */
146 
147    /***************************/
148    /*   MACD FIX - CLASSIC    */
149    /***************************/
150 
151    /***************************/
152    /*   MACD FIX - METASTOCK  */
153    /***************************/
154    { 1, TA_MACDFIX_TEST, 0, 251, 12, 26, 9, TA_COMPATIBILITY_METASTOCK, TA_SUCCESS,  33, 252-33, /* 25, 252-25,*/
155                                                           0, -1.2185,  /* MACD */
156                                                           0, -1.7119,  /* Signal */
157                                                           0, (-1.2185)-(-1.7119) }, /* Histogram */
158 
159    { 0, TA_MACDFIX_TEST, 0, 251, 12, 26, 9, TA_COMPATIBILITY_METASTOCK, TA_SUCCESS, 33, 252-33,
160                                                         252-34,  0.8764, /* MACD */
161                                                         252-34,  1.3533,   /* Signal */
162                                                         252-34,  (0.8764)-(1.3533)}, /* Histogram */
163    /* Test period inversion */
164    { 0, TA_MACDFIX_TEST, 0, 251, 26, 12, 9, TA_COMPATIBILITY_METASTOCK, TA_SUCCESS, 33, 252-33,
165                                                         252-34,  0.8764, /* MACD */
166                                                         252-34,  1.3533,   /* Signal */
167                                                         252-34,  (0.8764)-(1.3533)} /* Histogram */
168 
169 };
170 
171 #define NB_TEST (sizeof(tableTest)/sizeof(TA_Test))
172 
173 /**** Global functions definitions.   ****/
test_func_macd(TA_History * history)174 ErrorNumber test_func_macd( TA_History *history )
175 {
176    unsigned int i;
177    ErrorNumber retValue;
178 
179    for( i=0; i < NB_TEST; i++ )
180    {
181 
182       if( (int)tableTest[i].expectedNbElement > (int)history->nbBars )
183       {
184          printf( "TA_MACD Failed Bad Parameter for Test #%d (%d,%d)\n",
185                  i,
186                  tableTest[i].expectedNbElement,
187                  history->nbBars );
188          return TA_TESTUTIL_TFRR_BAD_PARAM;
189       }
190 
191       retValue = do_test( history, &tableTest[i] );
192       if( retValue != 0 )
193       {
194          printf( "TA_MACD Failed Test #%d (Code=%d)\n", i, retValue );
195          return retValue;
196       }
197    }
198 
199    /* All test succeed. */
200    return TA_TEST_PASS;
201 }
202 
203 /**** Local functions definitions.     ****/
rangeTestFunction(TA_Integer startIdx,TA_Integer endIdx,TA_Real * outputBuffer,TA_Integer * outputBufferInt,TA_Integer * outBegIdx,TA_Integer * outNbElement,TA_Integer * lookback,void * opaqueData,unsigned int outputNb,unsigned int * isOutputInteger)204 static TA_RetCode rangeTestFunction( TA_Integer    startIdx,
205                                      TA_Integer    endIdx,
206                                      TA_Real      *outputBuffer,
207                                      TA_Integer   *outputBufferInt,
208                                      TA_Integer   *outBegIdx,
209                                      TA_Integer   *outNbElement,
210                                      TA_Integer   *lookback,
211                                      void         *opaqueData,
212                                      unsigned int  outputNb,
213                                      unsigned int *isOutputInteger )
214 {
215    TA_RetCode retCode;
216    TA_RangeTestParam *testParam;
217    TA_Real *dummyBuffer1, *dummyBuffer2;
218    TA_Real *out1, *out2, *out3;
219 
220    (void)outputBufferInt;
221 
222    *isOutputInteger = 0;
223 
224    testParam = (TA_RangeTestParam *)opaqueData;
225 
226    dummyBuffer1 = TA_Malloc( ((endIdx-startIdx)+1)*sizeof(TA_Real));
227    if( !dummyBuffer1 )
228       return TA_ALLOC_ERR;
229 
230    dummyBuffer2 = TA_Malloc( ((endIdx-startIdx)+1)*sizeof(TA_Real));
231    if( !dummyBuffer2 )
232    {
233       TA_Free(  dummyBuffer1 );
234       return TA_ALLOC_ERR;
235    }
236 
237    switch( outputNb )
238    {
239    case 0:
240       out1 = outputBuffer;
241       out2 = dummyBuffer1;
242       out3 = dummyBuffer2;
243       break;
244    case 1:
245       out2 = outputBuffer;
246       out1 = dummyBuffer1;
247       out3 = dummyBuffer2;
248       break;
249    case 2:
250       out3 = outputBuffer;
251       out2 = dummyBuffer1;
252       out1 = dummyBuffer2;
253       break;
254    default:
255       TA_Free(  dummyBuffer1 );
256       TA_Free(  dummyBuffer2 );
257       return TA_BAD_PARAM;
258    }
259 
260    switch( testParam->test->testId )
261    {
262    case TA_MACDFIX_TEST:
263       retCode = TA_MACDFIX( startIdx,
264                             endIdx,
265                             testParam->close,
266                             testParam->test->optInSignalPeriod_2,
267                             outBegIdx, outNbElement,
268                             out1, out2, out3 );
269      *lookback = TA_MACDFIX_Lookback( testParam->test->optInSignalPeriod_2 );
270      break;
271    case TA_MACD_TEST:
272       retCode = TA_MACD(    startIdx,
273                             endIdx,
274                             testParam->close,
275                             testParam->test->optInFastPeriod,
276                             testParam->test->optInSlowPeriod,
277                             testParam->test->optInSignalPeriod_2,
278                             outBegIdx, outNbElement,
279                             out1, out2, out3 );
280 
281       *lookback = TA_MACD_Lookback( testParam->test->optInFastPeriod,
282                                     testParam->test->optInSlowPeriod,
283                                     testParam->test->optInSignalPeriod_2 );
284       break;
285    case TA_MACDEXT_TEST:
286       retCode = TA_MACDEXT( startIdx,
287                             endIdx,
288                             testParam->close,
289                             testParam->test->optInFastPeriod,
290                             TA_MAType_EMA,
291                             testParam->test->optInSlowPeriod,
292                             TA_MAType_EMA,
293                             testParam->test->optInSignalPeriod_2,
294                             TA_MAType_EMA,
295                             outBegIdx, outNbElement,
296                             out1, out2, out3 );
297 
298       *lookback = TA_MACDEXT_Lookback( testParam->test->optInFastPeriod,
299                                        TA_MAType_EMA,
300                                        testParam->test->optInSlowPeriod,
301                                        TA_MAType_EMA,
302                                        testParam->test->optInSignalPeriod_2,
303                                        TA_MAType_EMA );
304       break;
305    default:
306       retCode = TA_BAD_PARAM;
307    }
308 
309    TA_Free(  dummyBuffer1 );
310    TA_Free(  dummyBuffer2 );
311 
312    return retCode;
313 }
314 
do_test(const TA_History * history,const TA_Test * test)315 static ErrorNumber do_test( const TA_History *history,
316                             const TA_Test *test )
317 {
318    TA_RetCode retCode;
319    ErrorNumber errNb;
320    TA_Integer outBegIdx;
321    TA_Integer outNbElement;
322    TA_RangeTestParam testParam;
323 
324    retCode = TA_SetUnstablePeriod( TA_FUNC_UNST_EMA, 0 );
325    if( retCode != TA_SUCCESS )
326       return TA_TEST_TFRR_SETUNSTABLE_PERIOD_FAIL;
327 
328    TA_SetCompatibility( (TA_Compatibility)test->compatibility );
329 
330    /* Set to NAN all the elements of the gBuffers.  */
331    clearAllBuffers();
332 
333    /* Build the input. */
334    setInputBuffer( 0, history->close, history->nbBars );
335    setInputBuffer( 1, history->close, history->nbBars );
336    setInputBuffer( 2, history->close, history->nbBars );
337    setInputBuffer( 3, history->close, history->nbBars );
338 
339    CLEAR_EXPECTED_VALUE(0);
340    CLEAR_EXPECTED_VALUE(1);
341    CLEAR_EXPECTED_VALUE(2);
342 
343    /* Make a simple first call. */
344    switch( test->testId )
345    {
346    case TA_MACDFIX_TEST:
347       retCode = TA_MACDFIX( test->startIdx,
348                             test->endIdx,
349                             gBuffer[0].in,
350                             test->optInSignalPeriod_2,
351                             &outBegIdx, &outNbElement,
352                             gBuffer[0].out0,
353                             gBuffer[0].out1,
354                             gBuffer[0].out2 );
355       break;
356    case TA_MACD_TEST:
357       retCode = TA_MACD(test->startIdx,
358                         test->endIdx,
359                         gBuffer[0].in,
360                         test->optInFastPeriod,
361                         test->optInSlowPeriod,
362                         test->optInSignalPeriod_2,
363                         &outBegIdx, &outNbElement,
364                         gBuffer[0].out0,
365                         gBuffer[0].out1,
366                         gBuffer[0].out2 );
367       break;
368    case TA_MACDEXT_TEST:
369       retCode = TA_MACDEXT( test->startIdx,
370                             test->endIdx,
371                             gBuffer[0].in,
372                             test->optInFastPeriod,
373                             TA_MAType_EMA,
374                             test->optInSlowPeriod,
375                             TA_MAType_EMA,
376                             test->optInSignalPeriod_2,
377                             TA_MAType_EMA,
378                             &outBegIdx, &outNbElement,
379                             gBuffer[0].out0,
380                             gBuffer[0].out1,
381                             gBuffer[0].out2 );
382       break;
383    }
384 
385 
386    errNb = checkDataSame( gBuffer[0].in, history->close, history->nbBars );
387    if( errNb != TA_TEST_PASS )
388       return errNb;
389 
390    CHECK_EXPECTED_VALUE( gBuffer[0].out0, 0 );
391    CHECK_EXPECTED_VALUE( gBuffer[0].out1, 1 );
392    CHECK_EXPECTED_VALUE( gBuffer[0].out2, 2 );
393 
394    outBegIdx = outNbElement = 0;
395 
396    /* Make another call where the input and the output are the
397     * same buffer.
398     */
399    switch( test->testId )
400    {
401    case TA_MACDFIX_TEST:
402       retCode = TA_MACDFIX(
403                         test->startIdx,
404                         test->endIdx,
405                         gBuffer[1].in,
406                         test->optInSignalPeriod_2,
407                         &outBegIdx, &outNbElement,
408                         gBuffer[1].in,
409                         gBuffer[1].out1,
410                         gBuffer[1].out2 );
411       break;
412    case TA_MACD_TEST:
413       retCode = TA_MACD(test->startIdx,
414                         test->endIdx,
415                         gBuffer[1].in,
416                         test->optInFastPeriod,
417                         test->optInSlowPeriod,
418                         test->optInSignalPeriod_2,
419                         &outBegIdx, &outNbElement,
420                         gBuffer[1].in,
421                         gBuffer[1].out1,
422                         gBuffer[1].out2 );
423       break;
424    case TA_MACDEXT_TEST:
425       retCode = TA_MACDEXT( test->startIdx,
426                             test->endIdx,
427                             gBuffer[1].in,
428                             test->optInFastPeriod,
429                             TA_MAType_EMA,
430                             test->optInSlowPeriod,
431                             TA_MAType_EMA,
432                             test->optInSignalPeriod_2,
433                             TA_MAType_EMA,
434                             &outBegIdx, &outNbElement,
435                             gBuffer[1].in,
436                             gBuffer[1].out1,
437                             gBuffer[1].out2 );
438       break;
439    }
440 
441    /* The previous call should have the same output
442     * as this call.
443     *
444     * checkSameContent verify that all value different than NAN in
445     * the first parameter is identical in the second parameter.
446     */
447    errNb = checkSameContent( gBuffer[0].out0, gBuffer[1].in );
448    if( errNb != TA_TEST_PASS )
449       return errNb;
450 
451    CHECK_EXPECTED_VALUE( gBuffer[1].in,   0 );
452    CHECK_EXPECTED_VALUE( gBuffer[1].out1, 1 );
453    CHECK_EXPECTED_VALUE( gBuffer[1].out2, 2 );
454 
455    outBegIdx = outNbElement = 0;
456 
457    CLEAR_EXPECTED_VALUE(0);
458    CLEAR_EXPECTED_VALUE(1);
459    CLEAR_EXPECTED_VALUE(2);
460 
461    /* Make another call where the input and the output are the
462     * same buffer.
463     */
464    switch( test->testId )
465    {
466    case TA_MACDFIX_TEST:
467       retCode = TA_MACDFIX(
468                         test->startIdx,
469                         test->endIdx,
470                         gBuffer[2].in,
471                         test->optInSignalPeriod_2,
472                         &outBegIdx, &outNbElement,
473                         gBuffer[2].out1,
474                         gBuffer[2].in,
475                         gBuffer[2].out2 );
476       break;
477 
478    case TA_MACD_TEST:
479       retCode = TA_MACD(
480                         test->startIdx,
481                         test->endIdx,
482                         gBuffer[2].in,
483                         test->optInFastPeriod,
484                         test->optInSlowPeriod,
485                         test->optInSignalPeriod_2,
486                         &outBegIdx, &outNbElement,
487                         gBuffer[2].out1,
488                         gBuffer[2].in,
489                         gBuffer[2].out2 );
490       break;
491    case TA_MACDEXT_TEST:
492       retCode = TA_MACDEXT(
493                             test->startIdx,
494                             test->endIdx,
495                             gBuffer[2].in,
496                             test->optInFastPeriod,
497                             TA_MAType_EMA,
498                             test->optInSlowPeriod,
499                             TA_MAType_EMA,
500                             test->optInSignalPeriod_2,
501                             TA_MAType_EMA,
502                             &outBegIdx, &outNbElement,
503                             gBuffer[2].out1,
504                             gBuffer[2].in,
505                             gBuffer[2].out2 );
506       break;
507    }
508 
509    /* The previous call should have the same output
510     * as this call.
511     *
512     * checkSameContent verify that all value different than NAN in
513     * the first parameter is identical in the second parameter.
514     */
515    errNb = checkSameContent( gBuffer[1].out1, gBuffer[2].in );
516    if( errNb != TA_TEST_PASS )
517       return errNb;
518 
519    CHECK_EXPECTED_VALUE( gBuffer[2].out1, 0 );
520    CHECK_EXPECTED_VALUE( gBuffer[2].in,   1 );
521    CHECK_EXPECTED_VALUE( gBuffer[2].out2, 2 );
522 
523    outBegIdx = outNbElement = 0;
524 
525    CLEAR_EXPECTED_VALUE(0);
526    CLEAR_EXPECTED_VALUE(1);
527    CLEAR_EXPECTED_VALUE(2);
528 
529    /* Make another call where the input and the output are the
530     * same buffer.
531     */
532    switch( test->testId )
533    {
534    case TA_MACDFIX_TEST:
535       retCode = TA_MACDFIX( test->startIdx,
536                             test->endIdx,
537                             gBuffer[3].in,
538                             test->optInSignalPeriod_2,
539                             &outBegIdx, &outNbElement,
540                             gBuffer[3].out1,
541                             gBuffer[3].out2,
542                             gBuffer[3].in );
543       break;
544    case TA_MACD_TEST:
545       retCode = TA_MACD(test->startIdx,
546                         test->endIdx,
547                         gBuffer[3].in,
548                         test->optInFastPeriod,
549                         test->optInSlowPeriod,
550                         test->optInSignalPeriod_2,
551                         &outBegIdx, &outNbElement,
552                         gBuffer[3].out1,
553                         gBuffer[3].out2,
554                         gBuffer[3].in );
555       break;
556    case TA_MACDEXT_TEST:
557       retCode = TA_MACDEXT( test->startIdx,
558                             test->endIdx,
559                             gBuffer[3].in,
560                             test->optInFastPeriod,
561                             TA_MAType_EMA,
562                             test->optInSlowPeriod,
563                             TA_MAType_EMA,
564                             test->optInSignalPeriod_2,
565                             TA_MAType_EMA,
566                             &outBegIdx, &outNbElement,
567                             gBuffer[3].out1,
568                             gBuffer[3].out2,
569                             gBuffer[3].in );
570       break;
571    }
572 
573    /* The previous call should have the same output
574     * as this call.
575     *
576     * checkSameContent verify that all value different than NAN in
577     * the first parameter is identical in the second parameter.
578     */
579    errNb = checkSameContent( gBuffer[2].out2, gBuffer[3].in );
580    if( errNb != TA_TEST_PASS )
581       return errNb;
582 
583    CHECK_EXPECTED_VALUE( gBuffer[3].out1, 0 );
584    CHECK_EXPECTED_VALUE( gBuffer[3].out2, 1 );
585    CHECK_EXPECTED_VALUE( gBuffer[3].in,   2 );
586 
587    /* Do a systematic test of most of the
588     * possible startIdx/endIdx range.
589     */
590    testParam.test  = test;
591    testParam.close = history->close;
592 
593    if( test->doRangeTestFlag )
594    {
595       errNb = doRangeTest( rangeTestFunction,
596                            TA_FUNC_UNST_EMA,
597                            (void *)&testParam, 3, 0 );
598       if( errNb != TA_TEST_PASS )
599          return errNb;
600    }
601 
602    return TA_TEST_PASS;
603 }
604