unsigned int TA_FileSize( TA_FileHandle *handle ) { #if defined( USE_WIN32_API ) BY_HANDLE_FILE_INFORMATION bhfi; #endif TA_FileHandlePriv *fileHandlePriv; unsigned int fileSize; TA_ASSERT_RET( handle != NULL, 0 ); fileHandlePriv = (TA_FileHandlePriv *)handle; if( fileHandlePriv->streamAccess ) { /* Use the stream instead of the file. */ fileSize = TA_StreamSizeInByte( fileHandlePriv->stream ); } else { #if defined( USE_WIN32_API ) TA_ASSERT_RET( fileHandlePriv->handle != INVALID_HANDLE_VALUE, 0 ); GetFileInformationByHandle( fileHandlePriv->handle, &bhfi ); fileSize = bhfi.nFileSizeLow; #endif #if defined( USE_OSLAYER ) TA_ASSERT_RET( fileHandlePriv->handle != NULL, 0 ); fileSize = get_file_size( fileHandlePriv->path ); #endif } return fileSize; }
static int findTimestampIndex( const TA_PMPriv *pmPriv, const TA_Timestamp *exitTimestamp, int *idx ) { const TA_Timestamp *startDate; const TA_Timestamp *endDate; TA_DayOfWeek dayOfTheWeek; /* Return 0 when no index can be resolved. */ startDate = &pmPriv->startDate; endDate = &pmPriv->endDate; /* Make sure the exitTimestamp is within the start/end date. */ if( (TA_TimestampGreater(exitTimestamp,startDate)&&TA_TimestampLess(exitTimestamp,endDate)) || TA_TimestampEqual(exitTimestamp, startDate) || TA_TimestampEqual(exitTimestamp, endDate) ) { /* Make sure the exitTimestamp is NOT on week-end. Week-end * trades are currently ignored. */ dayOfTheWeek = TA_GetDayOfTheWeek( exitTimestamp ); if( (dayOfTheWeek != TA_SUNDAY) && (dayOfTheWeek != TA_SATURDAY) ) { TA_TimestampDeltaWeekday( startDate, exitTimestamp, (unsigned int *)idx ); *idx -= 1; #ifdef TA_DEBUG TA_ASSERT_RET( *idx >= 0, 0 ); TA_ASSERT_RET( (unsigned int)*idx < pmPriv->nbDailyBars, 0 ); TA_ASSERT_RET( TA_TimestampEqual(&pmPriv->arrayTimestamp[*idx], exitTimestamp ), 0 ); #endif return 1; } } /* No index can be found, initialize to zero, just to * be safe. */ *idx = 0; return 0; }
TA_ValueTreeNode *TA_FileIndexGoUpTreeValue( TA_FileIndexPriv *data ) { TA_ValueTreeNode *retValue; TA_Libc *libHandle; libHandle = data->libHandle; TA_ASSERT_RET( libHandle, data != NULL, (TA_ValueTreeNode *)NULL ); if( !data->currentNode ) return (TA_ValueTreeNode *)NULL; retValue = data->currentNode->parent; /* Change data->currentNode only if we can really go up... */ if( retValue ) data->currentNode = retValue; return retValue; }
/* Two very limited function to walk up/down in the Tree. * These functions are useful only when walking on a known linear portion * of the tree (when for each parent there is only one child). */ TA_ValueTreeNode *TA_FileIndexGoDownTreeValue( TA_FileIndexPriv *data ) { TA_ValueTreeNode *retValue; TA_Libc *libHandle; libHandle = data->libHandle; TA_ASSERT_RET( libHandle, data != NULL, (TA_ValueTreeNode *)NULL ); /* Go down using the first child only. */ if( (!data->currentNode) || (!data->currentNode->child) ) return NULL; retValue = TA_ListAccessHead( data->currentNode->child ); /* Change data->currentNode only if we really can go down... */ if( retValue ) data->currentNode = retValue; return retValue; }
const char *TA_FileSeqRead( TA_FileHandle *handle, unsigned int *nbByteRead ) { #if defined( USE_WIN32_API ) BOOL retValue; DWORD nbByteReadLocal; #else size_t nbByteReadLocal; #endif TA_FileHandlePriv *fileHandlePriv; const char *returnValue; TA_RetCode retCode; TA_ASSERT_RET( handle != NULL, (char *)NULL ); TA_ASSERT_RET( nbByteRead != NULL, (char *)NULL ); fileHandlePriv = (TA_FileHandlePriv *)handle; if( fileHandlePriv->streamAccess ) { /* Use the stream instead of the file. * Get the data chunk by chunk. */ retCode = TA_StreamAccessGetBuffer( fileHandlePriv->streamAccess, &returnValue, nbByteRead ); if( retCode != TA_SUCCESS ) return 0; } else { TA_ASSERT_RET( fileHandlePriv->allocBuffer != NULL, (char *)NULL ); TA_ASSERT_RET( fileHandlePriv->allocBufferSize >= 128, (char *)NULL ); *nbByteRead = 0; #if defined( USE_WIN32_API ) TA_ASSERT_RET( fileHandlePriv->handle != INVALID_HANDLE_VALUE, (char *)NULL ); retValue = ReadFile( fileHandlePriv->handle, fileHandlePriv->allocBuffer, fileHandlePriv->allocBufferSize, &nbByteReadLocal, NULL ); if( retValue == 0 ) return NULL; #else TA_ASSERT_RET( fileHandlePriv->handle != NULL, (char *)NULL ); if( feof(fileHandlePriv->handle) || ferror(fileHandlePriv->handle) ) return NULL; nbByteReadLocal = fread( fileHandlePriv->allocBuffer, 1, fileHandlePriv->allocBufferSize, fileHandlePriv->handle ); #endif *nbByteRead = nbByteReadLocal; if( *nbByteRead == 0 ) return NULL; returnValue = fileHandlePriv->allocBuffer; } return returnValue; }
TA_String *stringAllocNInternal( TA_StringCache *stringCache, const char *string, unsigned int maxNbChar, TA_CharCase caseType ) { TA_String *tmp; unsigned int hashIndex; char *hashEntry; TA_StringCachePriv *stringCachePriv; unsigned int newStringLength; int sameString; unsigned int i; #if !defined( TA_SINGLE_THREAD ) TA_RetCode retCode; #endif if( stringCache == NULL ) return NULL; stringCachePriv = (TA_StringCachePriv *)stringCache; if( !string ) return NULL; hashIndex = calcHash( string, caseType ); TA_ASSERT_RET( hashIndex < NB_CACHE_ENTRY, (TA_String *)NULL ); /* Evaluate the final length of the new string. */ newStringLength = strlen( string ); if( maxNbChar != 0 ) { if( maxNbChar < newStringLength ) newStringLength = maxNbChar; } #if !defined( TA_SINGLE_THREAD ) /* Get the semaphore for this cache. */ retCode = TA_SemaWait( &stringCachePriv->sema ); if( retCode != TA_SUCCESS ) return NULL; #endif /* Check if already in the hash table. If yes, re-use it. */ hashEntry = (char *)stringCachePriv->cache[ hashIndex ]; if( hashEntry && ((unsigned char)hashEntry[0] < 255) ) { /* Check that this is the same string, same size. */ if( (caseType == NO_CASE) && (!strncmp( string, &hashEntry[1], newStringLength)) && (hashEntry[newStringLength+1] == '\0') ) sameString = 1; else if( caseType == PATH ) { sameString = 1; for( i=0; i <= newStringLength && (sameString == 1); i++ ) { if( hashEntry[i+1] == '\0' ) sameString = 0; if( (string[i] != hashEntry[i+1]) && !TA_IsSeparatorChar(string[i]) ) sameString = 0; } if( sameString && (hashEntry[newStringLength+1] != '\0') ) sameString = 0; } else if( caseType == UPPER_CASE ) { sameString = 1; for( i=0; i <= newStringLength && (sameString == 1); i++ ) { if( hashEntry[i+1] == '\0' ) sameString = 0; if( (toupper(string[i]) != hashEntry[i+1]) ) sameString = 0; } if( sameString && (hashEntry[newStringLength+1] != '\0') ) sameString = 0; } else sameString = 0; if( sameString ) { tmp = stringDupInternal( (TA_String *)hashEntry ); #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &stringCachePriv->sema ); #endif return tmp; } } tmp = stringAllocInternal( string, newStringLength, caseType ); if( tmp != NULL ) { /* Store in cache. */ /* Delete previous entry in the same position in the cache. */ if( hashEntry ) stringFreeInternal( (TA_String *)hashEntry ); /* Keep track of this latest allocation. */ stringCachePriv->cache[hashIndex] = stringDupInternal( tmp ); } #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &stringCachePriv->sema ); #endif return tmp; }
/**** 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; }
static TA_Timestamp *allocTimestampArray( const TA_Timestamp *start, const TA_Timestamp *end, int *nbDays ) { TA_RetCode retCode; TA_Timestamp *array; int outIdx; TA_Timestamp curDate; TA_DayOfWeek dayOfTheWeek; TA_ASSERT_RET( TA_TimestampValidate(start) == TA_SUCCESS, (TA_Timestamp *)NULL ); TA_ASSERT_RET( TA_TimestampValidate(end ) == TA_SUCCESS, (TA_Timestamp *)NULL ); TA_ASSERT_RET( nbDays != NULL, (TA_Timestamp *)NULL ); /* Calculate the exact number of week days * between start and end inclusive. * Excluding week-ends. */ retCode = TA_TimestampDeltaWeekday( start, end, (unsigned int *)nbDays ); if( retCode != TA_SUCCESS ) return (TA_Timestamp *)NULL; /* Allocate the array. Add two element just to be on the safe side. */ array = TA_Malloc( sizeof( TA_Timestamp ) * ((*nbDays)+2) ); if( !array ) return (TA_Timestamp *)NULL; /* Fill up the array. */ TA_TimestampCopy( &curDate, start ); /* Write the start point, if it is a weekday. */ outIdx = 0; dayOfTheWeek = TA_GetDayOfTheWeek( &curDate ); if( (dayOfTheWeek != TA_SUNDAY) && (dayOfTheWeek != TA_SATURDAY) ) { TA_TimestampCopy( &array[outIdx], &curDate ); outIdx++; TA_NextWeekday( &curDate ); TA_ASSERT_RET( TA_TimestampValidate(&curDate) == TA_SUCCESS, (TA_Timestamp *)NULL ); } /* Count the number of weekday */ while( TA_TimestampLess( &curDate, end ) ) { TA_TimestampCopy( &array[outIdx], &curDate ); outIdx++; TA_NextWeekday( &curDate ); TA_ASSERT_RET( TA_TimestampValidate(&curDate) == TA_SUCCESS, (TA_Timestamp *)NULL ); } /* Check if the ending point is a weekday. */ if( TA_TimestampEqual( &curDate, end ) ) { dayOfTheWeek = TA_GetDayOfTheWeek( &curDate ); if( (dayOfTheWeek != TA_SUNDAY) && (dayOfTheWeek != TA_SATURDAY) ) TA_TimestampCopy( &array[outIdx++], &curDate ); } TA_ASSERT_RET( outIdx == (*nbDays), (TA_Timestamp *)NULL ); return array; }