TA_RetCode TA_TradeReportAlloc( TA_PM *pm, TA_TradeReport **tradeReportAllocated ) { TA_PMPriv *pmPriv; TA_TradeReport *tradeReport; TA_TradeReportPriv *tradeReportPriv; TA_List *tradeLogList; TA_TradeLogPriv *tradeLogPriv; TA_AllocatorForDataLog *allocator; TA_DataLogBlock *block; TA_List *listOfBlock; TA_DataLog *invalidDataLog; TA_DataLog *curDataLog; TA_Trade **tradePtr; TA_Timestamp *startDate; TA_Timestamp *endDate; TA_RetCode retCode; TA_Real tempReal; int nbTrade, nbTradeAdded, i; if( !tradeReportAllocated ) return TA_BAD_PARAM; *tradeReportAllocated = NULL; if( !pm ) return TA_BAD_PARAM; /* Make sure this TA_PM is a valid object */ pmPriv = (TA_PMPriv *)pm->hiddenData; if( !pmPriv || (pmPriv->magicNb != TA_PMPRIV_MAGIC_NB) ) return TA_BAD_OBJECT; tradeReport = TA_Malloc( sizeof( TA_TradeReport ) + sizeof( TA_TradeReportPriv ) ); if( !tradeReport ) return TA_ALLOC_ERR; memset( tradeReport, 0, sizeof( TA_TradeReport ) + sizeof( TA_TradeReportPriv ) ); tradeReportPriv = (TA_TradeReportPriv *)(((char *)tradeReport)+sizeof(TA_TradeReport)); tradeReportPriv->magicNb = TA_TRADEREPORT_MAGIC_NB; tradeReport->hiddenData = tradeReportPriv; /* TA_TradeReportFree can be safely called from this point. */ /* Get the number of closed trades */ tempReal = 0; retCode = TA_PMValue( pm, TA_PM_TOTAL_NB_OF_TRADE, TA_PM_ALL_TRADES, &tempReal ); if( retCode != TA_SUCCESS ) { TA_TradeReportFree( tradeReport ); return retCode; } nbTrade = (unsigned int)tempReal; tradeReport->nbTrades = nbTrade; if( nbTrade != 0 ) { startDate = &pmPriv->startDate; endDate = &pmPriv->endDate; tradePtr = (TA_Trade **)TA_Malloc( nbTrade*sizeof(const TA_Trade *)); tradeReport->trades = (const TA_Trade **)tradePtr; if( !tradePtr ) { TA_TradeReportFree( tradeReport ); return TA_ALLOC_ERR; } /* Iterate through all the closed trades. */ nbTradeAdded = 0; tradeLogList = &pmPriv->tradeLogList; tradeLogPriv = TA_ListAccessHead( tradeLogList ); if( !tradeLogPriv ) { TA_TradeReportFree( tradeReport ); return TA_NO_TRADE_LOG; } do { allocator = &tradeLogPriv->allocator; listOfBlock = &allocator->listOfDataLogBlock; block = TA_ListAccessHead( listOfBlock ); while( block ) { /* Process each blocks. */ invalidDataLog = allocator->nextAvailableTrade; curDataLog = block->array; for( i=0; i < TA_TRADE_BLOCK_SIZE; i++ ) { if( curDataLog == invalidDataLog ) { break; } else { /* Process each TA_DataLog being a trade (not an entry) * An entry have a negative 'quantity'. */ if( (curDataLog->u.trade.quantity > 0) && !TA_TimestampLess( &curDataLog->u.trade.entryTimestamp, startDate ) && !TA_TimestampGreater( &curDataLog->u.trade.exitTimestamp, endDate ) ) { /* Make sure not to exceed array size */ if( nbTradeAdded >= nbTrade ) { TA_TradeReportFree( tradeReport ); return TA_ALLOC_ERR; } tradePtr[nbTradeAdded++] = &curDataLog->u.trade; } } curDataLog++; } block = TA_ListAccessNext( listOfBlock ); } tradeLogPriv = TA_ListAccessNext( tradeLogList ); } while( tradeLogPriv ); /* Make sure all trades were initialized. */ if( nbTradeAdded != nbTrade ) { TA_TradeReportFree( tradeReport ); return TA_ALLOC_ERR; } /* Sort all trades in chronological order of exit. */ qsort( tradePtr, (size_t)nbTrade, sizeof(TA_Trade *), compareTrade ); } /* All succeed. Return pointer to caller. */ *tradeReportAllocated = tradeReport; return TA_SUCCESS; }
static ErrorNumber checkPMvalues( TA_PM *pm, int nbLongTrade, int nbShortTrade, TA_Real longNetProfit, TA_Real shortNetProfit ) { TA_RetCode retCode; TA_Real pmReadNbShortTrade, pmReadNbLongTrade, pmReadNbTotalTrade; TA_Real tempReal1, tempReal2; tempReal1 = tempReal2 = 0.0; /* Check all the TA_PM_TOTAL_NB_OF_TRADE. */ retCode = TA_PMValue( pm, TA_PM_TOTAL_NB_OF_TRADE, TA_PM_LONG_TRADES, &pmReadNbLongTrade ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value)=(%d,%d,%d,%g)\n", TA_PM_TOTAL_NB_OF_TRADE, TA_PM_LONG_TRADES, retCode, pmReadNbLongTrade ); return TA_PM_CHECKVALUE_FAILED_0; } retCode = TA_PMValue( pm, TA_PM_TOTAL_NB_OF_TRADE, TA_PM_SHORT_TRADES, &pmReadNbShortTrade ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value)=(%d,%d,%d,%g)\n", TA_PM_TOTAL_NB_OF_TRADE, TA_PM_SHORT_TRADES, retCode, pmReadNbShortTrade ); return TA_PM_CHECKVALUE_FAILED_1; } retCode = TA_PMValue( pm, TA_PM_TOTAL_NB_OF_TRADE, TA_PM_ALL_TRADES, &pmReadNbTotalTrade ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value)=(%d,%d,%d,%g)\n", TA_PM_TOTAL_NB_OF_TRADE, TA_PM_ALL_TRADES, retCode, pmReadNbTotalTrade ); return TA_PM_CHECKVALUE_FAILED_2; } if( ((nbShortTrade+nbLongTrade) != pmReadNbTotalTrade) || (nbShortTrade != pmReadNbShortTrade) || (nbLongTrade != pmReadNbLongTrade) ) { printRetCode( retCode ); printf( "Failed: invalid nb of trade (short,pmshort,long,pmlong,total,pmtotal)=(%d,%d,%d,%d,%d,%d)\n", nbShortTrade, (int)pmReadNbShortTrade, nbLongTrade, (int)pmReadNbLongTrade, (nbShortTrade+nbLongTrade), (int)pmReadNbTotalTrade ); return TA_PM_CHECKVALUE_FAILED_3; } /* Check all the value related to net profits. * shortNetProfit+longNetProfit = (TA_PM_TOTAL_NET_PROFIT, TA_PM_ALL_TRADES) * shortNetProfit = (TA_PM_TOTAL_NET_PROFIT, TA_PM_SHORT_TRADES) * longNetProfit = (TA_PM_TOTAL_NET_PROFIT, TA_PM_LONG_TRADES) * shortNetProfit = (TA_PM_PROFIT, TA_PM_SHORT_TRADES)+(TA_PM_LOSS, TA_PM_SHORT_TRADES) * longNetProfit = (TA_PM_PROFIT, TA_PM_LONG_TRADES)+(TA_PM_LOSS, TA_PM_LONG_TRADES) */ retCode = TA_PMValue( pm, TA_PM_TOTAL_NET_PROFIT, TA_PM_ALL_TRADES, &tempReal1 ); if( ((retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE)) || (tempReal1 != (shortNetProfit+longNetProfit)) ) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value,value)=(%d,%d,%d,%g,%g)\n", TA_PM_TOTAL_NET_PROFIT, TA_PM_ALL_TRADES, retCode, tempReal1, shortNetProfit+longNetProfit ); return TA_PM_CHECKVALUE_FAILED_4; } retCode = TA_PMValue( pm, TA_PM_TOTAL_NET_PROFIT, TA_PM_LONG_TRADES, &tempReal1 ); if( ((retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE)) || (tempReal1 != longNetProfit) ) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value,value)=(%d,%d,%d,%g,%g)\n", TA_PM_TOTAL_NET_PROFIT, TA_PM_LONG_TRADES, retCode, tempReal1, longNetProfit ); return TA_PM_CHECKVALUE_FAILED_5; } retCode = TA_PMValue( pm, TA_PM_TOTAL_NET_PROFIT, TA_PM_SHORT_TRADES, &tempReal2 ); if( ((retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE)) || (tempReal2 != shortNetProfit) ) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value,value)=(%d,%d,%d,%g,%g)\n", TA_PM_TOTAL_NET_PROFIT, TA_PM_SHORT_TRADES, retCode, tempReal1, shortNetProfit ); return TA_PM_CHECKVALUE_FAILED_6; } retCode = TA_PMValue( pm, TA_PM_GROSS_PROFIT, TA_PM_SHORT_TRADES, &tempReal1 ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value,value)=(%d,%d,%d,%g,%g)\n", TA_PM_GROSS_PROFIT, TA_PM_SHORT_TRADES, retCode, tempReal1, tempReal2 ); return TA_PM_CHECKVALUE_FAILED_7; } retCode = TA_PMValue( pm, TA_PM_GROSS_LOSS, TA_PM_SHORT_TRADES, &tempReal2 ); if( ((retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE)) || (shortNetProfit != (tempReal1+tempReal2))) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value,value)=(%d,%d,%d,%g,%g,%g)\n", TA_PM_GROSS_LOSS, TA_PM_SHORT_TRADES, retCode, tempReal1, tempReal2, shortNetProfit ); return TA_PM_CHECKVALUE_FAILED_8; } retCode = TA_PMValue( pm, TA_PM_GROSS_PROFIT, TA_PM_LONG_TRADES, &tempReal1 ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value,value)=(%d,%d,%d,%g,%g)\n", TA_PM_GROSS_PROFIT, TA_PM_LONG_TRADES, retCode, tempReal1, tempReal2 ); return TA_PM_CHECKVALUE_FAILED_9; } retCode = TA_PMValue( pm, TA_PM_GROSS_LOSS, TA_PM_LONG_TRADES, &tempReal2 ); if( ((retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE)) || (longNetProfit != (tempReal1+tempReal2))) { printRetCode( retCode ); printf( "Failed: TA_PMValue (valueId,grpId,retCode,value,value)=(%d,%d,%d,%g,%g,%g)\n", TA_PM_GROSS_LOSS, TA_PM_SHORT_TRADES, retCode, tempReal1, tempReal2, longNetProfit ); return TA_PM_CHECKVALUE_FAILED_10; } return TA_TEST_PASS; }
static ErrorNumber test_valueId( TA_PMValueIdTest *test ) { unsigned int i; TA_TradeLog *tradeLog; TA_PM *pm; ErrorNumber errorNumber; TA_RetCode retCode; TA_Real theValue; const char *tempStr; /* Allocate and build the TA_TradeLog */ retCode = TA_TradeLogAlloc( &tradeLog ); if( retCode != TA_SUCCESS ) return TA_PM_TEST_VALUE_ID_FAILED_0; /* Add all the transaction. For simplicity, make these * all the same instrument. */ #define TA_SAFETY_NET_LIMIT 100 i = 0; while( (((void *)test->inputs[i].type) != ((void *)-1)) && (i<TA_SAFETY_NET_LIMIT) ) { retCode = TA_TradeLogAdd( tradeLog, &test->inputs[i] ); if( retCode != TA_SUCCESS ) { printRetCode( retCode ); TA_TradeLogFree( tradeLog ); return TA_PM_TEST_VALUE_ID_FAILED_1; } i++; } if( i >= TA_SAFETY_NET_LIMIT ) { printf( "Failed: Number of transaction exceed %d limit\n", TA_SAFETY_NET_LIMIT ); return TA_PM_TEST_VALUE_ID_FAILED_2; } #undef TA_SAFETY_NET_LIMIT /* Build the TA_PM */ retCode = TA_PMAlloc( &test->startDate, &test->endDate, test->initialCapital, &pm ); if( retCode != TA_SUCCESS ) { printRetCode( retCode ); TA_TradeLogFree( tradeLog ); return TA_PM_TEST_VALUE_ID_FAILED_3; } /* Add the trade log to that PM */ retCode = TA_PMAddTradeLog( pm, tradeLog ); if( retCode != TA_SUCCESS ) { printRetCode( retCode ); return TA_PM_TEST_VALUE_ID_FAILED_4; } /* Test the report feature. Again just to detect * software hanging/bad pointer. */ errorNumber = test_report( pm, 0 ); if( errorNumber != TA_TEST_PASS ) return errorNumber; /* Check the requested TA_PMArrayId */ #define TA_SAFETY_NET_LIMIT 30 i=0; while( (((int)test->toCheck[i].id) != -1) && (i<TA_SAFETY_NET_LIMIT) ) { switch( test->toCheck[i].grp ) { case TA_PM_ALL_TRADES: tempStr = "TA_PM_ALL_TRADES"; break; case TA_PM_SHORT_TRADES: tempStr = "TA_PM_SHORT_TRADES"; break; case TA_PM_LONG_TRADES: tempStr = "TA_PM_LONG_TRADES"; break; default: tempStr = "Invalid Group Id"; } retCode = TA_PMValue( pm, test->toCheck[i].id, test->toCheck[i].grp, &theValue ); if( retCode != test->toCheck[i].expectedRetCode ) { printRetCode( test->toCheck[i].expectedRetCode ); printRetCode( retCode ); printf( "Failed: TA_PMValue expectedRetCode != retCode (%d != %d)\n", test->toCheck[i].expectedRetCode, retCode ); printf( "Failed: For %d:%s %d:%s\n", test->toCheck[i].id, TA_PMValueIdString(test->toCheck[i].id), test->toCheck[i].grp, tempStr ); return TA_PM_TEST_VALUE_ID_FAILED_5; } if( !TA_REAL_EQ(theValue,test->toCheck[i].expectedValue,0.01) ) { printf( "Failed: TA_PMValue expectedValue != theValue (%f != %f)\n", test->toCheck[i].expectedValue, theValue ); printf( "Failed: For %d:%s %d:%s\n", test->toCheck[i].id, TA_PMValueIdString(test->toCheck[i].id), test->toCheck[i].grp, tempStr ); return TA_PM_TEST_VALUE_ID_FAILED_6; } i++; } if( i >= TA_SAFETY_NET_LIMIT ) { printf( "Failed: Number of checks exceed %d limit\n", TA_SAFETY_NET_LIMIT ); return TA_PM_TEST_VALUE_ID_FAILED_7; } #undef TA_SAFETY_NET_LIMIT /* Check for any potential software hanging/bad pointer. */ errorNumber = checkNoHang( pm ); if( errorNumber != TA_TEST_PASS ) return errorNumber; /* Free up everything */ retCode = TA_TradeLogFree( tradeLog ); if( retCode != TA_SUCCESS ) { printRetCode( retCode ); return TA_PM_TEST_VALUE_ID_FAILED_8; } retCode = TA_PMFree( pm ); if( retCode != TA_SUCCESS ) { printRetCode( retCode ); return TA_PM_TEST_VALUE_ID_FAILED_9; } return TA_TEST_PASS; }
static ErrorNumber checkNoHang( TA_PM *pm ) { int i, j, k; TA_Real firstValue, secondValue; TA_RetCode retCode; /* Call 5 of the value at random. */ for( k=0; k < 5; k++ ) { i = rand()%TA_PM_NB_VALUEID; j = rand()%TA_PM_NB_GROUP; firstValue = 1.1111; retCode = TA_PMValue( pm, i, j, &firstValue ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "checkNoHang rand return error for first call (%d,%d,%d)\n", i, j, retCode ); return TA_PM_ERR_CHECK_NO_HANG_1; } secondValue = 2.2222; retCode = TA_PMValue( pm, i, j, &secondValue ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "checkNoHang rand return error for second call (%d,%d,%d)\n", i, j, retCode ); return TA_PM_ERR_CHECK_NO_HANG_2; } if( (retCode != TA_VALUE_NOT_APPLICABLE) && (firstValue != secondValue) ) { printf( "checkNoHang rand values not consistent (%d,%d,%g,%g)\n", i, j, firstValue, secondValue ); return TA_PM_ERR_CHECK_NO_HANG_3; } } /* Now systematically go through all the possible * values. * * The goal is just to try to break things by possibly * causing hanging, bad pointer access or memory leak. * * The call is done twice. The same value should be * always returned. */ for( i=0; i < TA_PM_NB_VALUEID; i++ ) { for( j=0; j < TA_PM_NB_GROUP; j++ ) { firstValue = 3.3333; retCode = TA_PMValue( pm, i, j, &firstValue ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "checkNoHang return error for first call (%d,%d,%d)\n", i, j, retCode ); return TA_PM_ERR_CHECK_NO_HANG_4; } secondValue = 4.4444; retCode = TA_PMValue( pm, i, j, &secondValue ); if( (retCode != TA_SUCCESS) && (retCode != TA_VALUE_NOT_APPLICABLE) ) { printRetCode( retCode ); printf( "checkNoHang return error for second call (%d,%d,%d)\n", i, j, retCode ); return TA_PM_ERR_CHECK_NO_HANG_5; } if( (retCode != TA_VALUE_NOT_APPLICABLE) && (firstValue != secondValue) ) { printf( "checkNoHang values not consistent (%d,%d,%g,%g)\n", i, j, firstValue, secondValue ); return TA_PM_ERR_CHECK_NO_HANG_6; } } } return TA_TEST_PASS; }
/**** Global functions definitions. ****/ TA_RetCode TA_PMArrayAlloc( TA_PM *pm, TA_PMArrayId arrayId, TA_PMGroup grp, TA_Period period, TA_PMArray **allocatedArray ) { TA_PMPriv *pmPriv; TA_List *tradeLogList; TA_TradeLogPriv *tradeLogPriv; int timeSerieSize; TA_RetCode retCode; TA_PMArray *newPMArray; unsigned int finalNbBars; TA_Real *finalData; TA_Timestamp *finalTimestamp; if( !allocatedArray ) return TA_BAD_PARAM; *allocatedArray = NULL; if( !pm || (arrayId >= TA_PM_NB_ARRAYID) || (grp >= TA_PM_NB_GROUP) ) return TA_BAD_PARAM; /* Make sure 'pm' is a ptr on a valid object */ pmPriv = (TA_PMPriv *)pm->hiddenData; if( pmPriv->magicNb != TA_PMPRIV_MAGIC_NB ) return TA_BAD_OBJECT; #if 0 /* Get the number of trade that applies to the period. * Doing so will also force the update of all * "basic calculation" if needed. */ retCode = TA_PMValue( pm, TA_PM_TOTAL_NB_OF_TRADE, TA_PM_ALL_TRADES, &nbTrade ); if( retCode != TA_SUCCESS ) return retCode; #endif /* Because the startDate/endDate are fix in the * lifetime of a TA_PM, all the cached time series * are allocated once here and freed only when the * TA_PM is freed. */ if( !pmPriv->arrayTimestamp ) { /* Allocate the timestamps (excluding week-end) * from [startDate..endDate] inclusive. * There is only one array of timestamps for all the * time series. */ pmPriv->arrayTimestamp = allocTimestampArray( &pmPriv->startDate, &pmPriv->endDate, (int *)&pmPriv->nbDailyBars ); if( !pmPriv->arrayTimestamp ) return TA_ALLOC_ERR; } if( !(pmPriv->flags & TA_PMARRAYCACHE_CALCULATED) ) { /* The cached time serie needs to be recalculated * from scratch. */ tradeLogList = &pmPriv->tradeLogList; tradeLogPriv = TA_ListAccessHead( tradeLogList ); if( !tradeLogPriv ) return TA_NO_TRADE_LOG; else { /* Make sure all required cached time series are correctly * allocated. */ timeSerieSize = sizeof(TA_Real)*pmPriv->nbDailyBars; #define TRY_ALLOC_IF_NULL(x) { \ if( !x ) \ { \ x = TA_Malloc( timeSerieSize ); \ if( !x ) \ return TA_ALLOC_ERR; \ } } TRY_ALLOC_IF_NULL( pmPriv->shortArrayCache.investment ); TRY_ALLOC_IF_NULL( pmPriv->shortArrayCache.profit ); TRY_ALLOC_IF_NULL( pmPriv->longArrayCache.investment ); TRY_ALLOC_IF_NULL( pmPriv->longArrayCache.profit ); #undef TRY_ALLOC_IF_NULL /* Reset to zero all the timeseries. */ memset( pmPriv->shortArrayCache.investment, 0, timeSerieSize ); memset( pmPriv->shortArrayCache.profit, 0, timeSerieSize ); memset( pmPriv->longArrayCache.investment, 0, timeSerieSize ); memset( pmPriv->longArrayCache.profit, 0, timeSerieSize ); /* Iterate through all the TA_TradeLog */ do { if( !(tradeLogPriv->flags & TA_PMARRAYCACHE_CALCULATED) ) processCache( pmPriv, tradeLogPriv ); tradeLogPriv = TA_ListAccessNext( tradeLogList ); } while( tradeLogPriv ); } pmPriv->flags |= TA_PMARRAYCACHE_CALCULATED; } switch( arrayId ) { case TA_PM_ARRAY_EQUITY: if( !(pmPriv->flags & TA_EQUITY_CALCULATED) ) { /* Allocate the daily equity. * Keep it cached in "pmPriv->equity". */ retCode = processDailyEquityArray(pmPriv,grp); if( retCode != TA_SUCCESS ) return retCode; pmPriv->flags |= TA_EQUITY_CALCULATED; } /* If requested is not daily, translate to the * new period. */ if( period == TA_DAILY ) { finalTimestamp = pmPriv->arrayTimestamp; finalData = pmPriv->equity; finalNbBars = pmPriv->nbDailyBars; } else { retCode = equityPeriodTransform( pmPriv, period, &finalNbBars, &finalTimestamp, &finalData ); if( retCode != TA_SUCCESS ) return retCode; } break; /*case TA_PM_ARRAY_RETURNS: break;*/ default: return TA_BAD_PARAM; } TA_ASSERT_RET( pmPriv->arrayTimestamp != NULL, TA_INTERNAL_ERROR(122) ); TA_ASSERT_RET( pmPriv->equity != NULL, TA_INTERNAL_ERROR(123) ); TA_ASSERT_RET( finalData != NULL, TA_INTERNAL_ERROR(124) ); TA_ASSERT_RET( finalTimestamp != NULL, TA_INTERNAL_ERROR(125) ); /* At last, allocate and fill up the TA_PMArray. */ newPMArray = TA_Malloc( sizeof( TA_PMArray ) ); if( !newPMArray ) return TA_ALLOC_ERR; newPMArray->arrayId = arrayId; newPMArray->grp = grp; newPMArray->period = period; newPMArray->data = finalData; newPMArray->timestamp = finalTimestamp; newPMArray->nbData = finalNbBars; newPMArray->hiddenData = pm; *allocatedArray = newPMArray; return TA_SUCCESS; }