static TA_RetCode getGroupId( const char *groupString, unsigned int *groupId ) #endif { #ifdef TA_GEN_CODE TA_PROLOG; #endif unsigned int i; #ifdef TA_GEN_CODE TA_TRACE_BEGIN( libHandle, getgroupId ); TA_ASSERT( libHandle, groupString != NULL ); TA_ASSERT( libHandle, groupId != NULL ); #endif for( i=0; i < TA_NB_GROUP_ID; i++ ) { if( strcmp( TA_GroupString[i], groupString ) == 0 ) { *groupId = i; #ifdef TA_GEN_CODE TA_TRACE_RETURN( TA_SUCCESS ); #else return TA_SUCCESS; #endif } } #ifdef TA_GEN_CODE TA_TRACE_RETURN( TA_GROUP_NOT_FOUND ); #else return TA_GROUP_NOT_FOUND; #endif }
static TA_RetCode getFuncNameByIdx( TA_GroupId groupId, unsigned int idx, const char **stringPtr ) #endif { #ifdef TA_GEN_CODE /* Code used only when compiled with gen_code. */ TA_PROLOG; unsigned int curIdx; unsigned int i, j, found; const TA_FuncDef **funcDefTable; unsigned int tableSize; const TA_FuncInfo *funcInfo; TA_TRACE_BEGIN( libHandle, getFuncNameByIdx ); TA_ASSERT( libHandle, stringPtr != NULL ); curIdx = 0; found = 0; for( i=0; (i < 26) && !found; i++ ) { funcDefTable = TA_DEF_Tables[i]; tableSize = *(TA_DEF_TablesSize[i]); for( j=0; (j < tableSize) && !found; j++ ) { if( funcDefTable[j]->groupId == groupId ) { if( idx == curIdx ) { funcInfo = funcDefTable[j]->funcInfo; TA_ASSERT( libHandle, funcInfo != NULL ); *stringPtr = funcInfo->name; found = 1; } curIdx++; } } } TA_ASSERT( libHandle, found == 1 ); TA_ASSERT( libHandle, *stringPtr != NULL ); TA_TRACE_RETURN( TA_SUCCESS ); #else /* Optimized code in the final library. */ const TA_FuncDef **funcDefTable; const TA_FuncInfo *funcInfo; funcDefTable = TA_PerGroupFuncDef[groupId]; funcInfo = funcDefTable[idx]->funcInfo; *stringPtr = funcInfo->name; return TA_SUCCESS; #endif }
TA::detail::DistEval<typename Op::result_type, Policy> make_contract_eval( const TA::detail::DistEval<LeftTile, Policy>& left, const TA::detail::DistEval<RightTile, Policy>& right, madness::World& world, const typename TA::detail::DistEval<typename Op::result_type, Policy>::shape_type& shape, const std::shared_ptr<typename TA::detail::DistEval< typename Op::result_type, Policy>::pmap_interface>& pmap, const TA::Permutation& perm, const Op& op) { TA_ASSERT(left.range().rank() == op.left_rank()); TA_ASSERT(right.range().rank() == op.right_rank()); TA_ASSERT((perm.dim() == op.result_rank()) || !perm); // Define the impl type typedef TA::detail::Summa< TA::detail::DistEval<LeftTile, Policy>, TA::detail::DistEval<RightTile, Policy>, Op, Policy> impl_type; // Precompute iteration range data const unsigned int num_contract_ranks = op.num_contract_ranks(); const unsigned int left_end = op.left_rank(); const unsigned int left_middle = left_end - num_contract_ranks; const unsigned int right_end = op.right_rank(); // Construct a vector TiledRange1 objects from the left- and right-hand // arguments that will be used to construct the result TiledRange. Also, // compute the fused outer dimension sizes, number of tiles and elements, // for the contraction. typename impl_type::trange_type::Ranges ranges(op.result_rank()); std::size_t M = 1ul, m = 1ul, N = 1ul, n = 1ul; std::size_t pi = 0ul; for(unsigned int i = 0ul; i < left_middle; ++i) { ranges[(perm ? perm[pi++] : pi++)] = left.trange().data()[i]; M *= left.range().extent(i); m *= left.trange().elements_range().extent(i); } for(std::size_t i = num_contract_ranks; i < right_end; ++i) { ranges[(perm ? perm[pi++] : pi++)] = right.trange().data()[i]; N *= right.range().extent(i); n *= right.trange().elements_range().extent(i); } // Compute the number of tiles in the inner dimension. std::size_t K = 1ul; for(std::size_t i = left_middle; i < left_end; ++i) K *= left.range().extent(i); // Construct the result range typename impl_type::trange_type trange(ranges.begin(), ranges.end()); // Construct the process grid TA::detail::ProcGrid proc_grid(world, M, N, m, n); return TA::detail::DistEval<typename Op::result_type, Policy>( std::shared_ptr<impl_type>( new impl_type(left, right, world, trange, shape, pmap, perm, op, K, proc_grid))); }
TA_RetCode TA_FileSeqClose( TA_FileHandle *handle ) { TA_PROLOG TA_RetCode retCode; TA_FileHandlePriv *fileHandlePriv; TA_SystemGlobal *global; #if defined( USE_WIN32_API ) DWORD win32Error; BOOL retValue; #endif TA_TRACE_BEGIN( TA_FileSeqClose ); retCode = TA_GetGlobal( &TA_SystemGlobalControl, (void **)&global ); if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } TA_ASSERT( handle != NULL ); fileHandlePriv = (TA_FileHandlePriv *)handle; if( fileHandlePriv ) { #if defined( USE_WIN32_API ) if( fileHandlePriv->handle != INVALID_HANDLE_VALUE ) { retValue = CloseHandle( fileHandlePriv->handle ); if( retValue == 0 ) { win32Error = GetLastError(); global->lastError = win32Error; TA_FATAL( NULL, 0, win32Error ); } } if( fileHandlePriv->allocBuffer ) { freeDiskBuffer( fileHandlePriv->allocBuffer, fileHandlePriv->allocBufferSize ); } #endif #if defined( USE_OSLAYER ) if( fileHandlePriv->handle != NULL ) fclose( fileHandlePriv->handle ); if( fileHandlePriv->allocBuffer ) TA_Free( fileHandlePriv->allocBuffer ); #endif if( fileHandlePriv->streamAccess ) { TA_StreamAccessFree( fileHandlePriv->streamAccess ); } TA_Free( fileHandlePriv ); } TA_TRACE_RETURN( TA_SUCCESS ); }
/* Allows to dynamically add a mini-driver. */ TA_RetCode TA_SQL_AddMinidriver( const char scheme[], const TA_SQL_Minidriver *minidriver ) { TA_PROLOG TA_String *schemeStr; TA_StringCache *cache; TA_RetCode retCode; TA_TRACE_BEGIN( TA_SQL_AddMinidriver ); if( !minidriverDict ) { minidriverDict = TA_DictAlloc( TA_DICT_KEY_ONE_STRING, NULL ); if( !minidriverDict ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } } cache = TA_GetGlobalStringCache(); TA_ASSERT( cache != NULL ); schemeStr = TA_StringAlloc( cache, scheme ); if( !schemeStr ) { TA_DictFree(minidriverDict); TA_TRACE_RETURN( TA_ALLOC_ERR ); } retCode = TA_DictAddPair_S( minidriverDict, schemeStr, (void *)minidriver ); TA_StringFree( cache, schemeStr ); TA_TRACE_RETURN( retCode ); }
static TA_RetCode getGroupSize( TA_GroupId groupId, unsigned int *groupSize ) #endif { #ifdef TA_GEN_CODE /* Code used only when compiled with gen_code. */ TA_PROLOG; unsigned int i, j; const TA_FuncDef **funcDefTable; const TA_FuncDef *funcDef; unsigned int tableSize; unsigned int nbFuncFound; TA_TRACE_BEGIN( libHandle, getGroupSize ); TA_ASSERT( libHandle, groupId < TA_NB_GROUP_ID ); TA_ASSERT( libHandle, groupId < TA_NB_GROUP_ID ); TA_ASSERT( libHandle, groupSize != NULL ); nbFuncFound = 0; for( i=0; i < 26; i++ ) { funcDefTable = TA_DEF_Tables[i]; tableSize = *(TA_DEF_TablesSize[i]); for( j=0; j < tableSize; j++ ) { funcDef = funcDefTable[j]; if( funcDef && (funcDef->groupId == groupId) ) nbFuncFound++; } } *groupSize = nbFuncFound; TA_TRACE_RETURN( TA_SUCCESS ); #else /* Optimized code in the final library. */ *groupSize = TA_PerGroupSize[groupId]; return TA_SUCCESS; #endif }
/**** Global functions definitions. ****/ TA_RetCode TA_HistoryCheckInternal( TA_Libc *libHandle, TA_Period expectedPeriod, const TA_Timestamp *expectedStart, const TA_Timestamp *expectedEnd, TA_Field fieldToCheck, const TA_History *history, unsigned int *faultyIndex, unsigned int *faultyField ) { TA_PROLOG; unsigned int allFieldNull; (void)faultyField; (void)faultyIndex; (void)fieldToCheck; (void)expectedEnd; (void)expectedStart; TA_TRACE_BEGIN( libHandle, TA_HistoryCheckInternal ); TA_ASSERT( libHandle, history != NULL ); /* Period shall be always set in the history. */ if( history->period != expectedPeriod ) { TA_TRACE_RETURN( TA_UNKNOWN_ERR ); } /* Verify that an empty history is really empty. */ if( (history->open == NULL) && (history->high == NULL) && (history->low == NULL) && (history->close == NULL) && (history->volume == NULL) && (history->openInterest == NULL) && (history->timestamp == NULL) ) { allFieldNull = 1; if( history->nbBars != 0 ) { TA_TRACE_RETURN( TA_UNKNOWN_ERR ); } } else allFieldNull = 0; if( (history->nbBars == 0) && !allFieldNull ) { TA_TRACE_RETURN( TA_UNKNOWN_ERR ); } /* !!! Some more runtime verification could be added here... */ TA_TRACE_RETURN( TA_SUCCESS ); }
void SQLCode::_GetSQLFormat(const std::string& strSQLKey, SQLStatement& strSQLFormats) { ThreadGuard guard(m_threadLock); // avoid threads racing TA_ASSERT(NULL != m_pSqlFileHelper, "sql file helper handler is null."); m_pSqlFileHelper->getSQLString(strSQLKey, strSQLFormats); if (strSQLFormats.strCommon.empty() && strSQLFormats.strMySQL.empty() && strSQLFormats.strSqlite.empty()) { TA_THROW(BadParamCount("Cannot find the SQL statement in the hash-table")); } }
/* Like TA_FileSeqOpen, but work with a stream instead. */ TA_RetCode TA_FileSeqOpenFromStream( TA_Stream *stream, TA_FileHandle **handle ) { TA_PROLOG TA_FileHandlePriv *fileHandlePriv; TA_TRACE_BEGIN( TA_FileSeqOpen ); TA_ASSERT( stream != NULL ); TA_ASSERT( handle != NULL ); /* Allocate the private file handle. */ fileHandlePriv = (TA_FileHandlePriv *)TA_Malloc( sizeof( TA_FileHandlePriv ) ); if( !fileHandlePriv ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } memset( fileHandlePriv, 0, sizeof( TA_FileHandlePriv ) ); /* There is NO file... */ #if defined( USE_WIN32_API ) fileHandlePriv->handle = INVALID_HANDLE_VALUE; #endif #if defined( USE_OSLAYER ) fileHandlePriv->handle = (FILE *)NULL; #endif /* ... use a stream instead. */ fileHandlePriv->stream = stream; fileHandlePriv->streamAccess = TA_StreamAccessAlloc( stream ); if( !fileHandlePriv->streamAccess ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } /* Success! Return the info to the caller. */ *handle = (TA_FileHandle *)fileHandlePriv; TA_TRACE_RETURN( TA_SUCCESS ); }
// makes tiles of fluctuating sizes // if n = average tile size // this will produce tiles of these sizes: n+1, n-1, n+2, n-2, etc. // the last tile absorbs the remainder std::vector<unsigned int> make_tiling(unsigned int range_size, unsigned int ntiles) { const auto average_tile_size = range_size / ntiles; TA_ASSERT(average_tile_size > ntiles); std::vector<unsigned int> result(ntiles+1); result[0] = 0; for(long t=0; t!=ntiles-1; ++t) { result[t+1] = result[t] + average_tile_size + ((t%2==0)?(t+1):(-t)); } result[ntiles] = range_size; return result; }
static TA_RetCode TA_SystemGlobalShutdown( void *globalAllocated ) { TA_PROLOG TA_RetCode retCode, finalRetCode; TA_SystemGlobal *global; TA_TRACE_BEGIN( TA_SystemGlobalShutdown ); /* No need to shutdown if the initialization failed. */ if( globalAllocated == NULL ) { TA_TRACE_RETURN( TA_SUCCESS ); } finalRetCode = TA_SUCCESS; global = (TA_SystemGlobal *)globalAllocated; if( global->dirnameCache ) { retCode = TA_StringCacheFree( global->dirnameCache ); TA_ASSERT( retCode == TA_SUCCESS ); if( retCode != TA_SUCCESS ) finalRetCode = retCode; } if( global->filenameCache ) { retCode = TA_StringCacheFree( global->filenameCache ); TA_ASSERT( retCode == TA_SUCCESS ); if( retCode != TA_SUCCESS ) finalRetCode = retCode; } TA_Free( global ); TA_TRACE_RETURN( finalRetCode ); }
TA_RetCode TA_FileIndexAddTreeValue( TA_FileIndexPriv *data, TA_String *string, TA_ValueTreeNode **added ) { TA_PROLOG; TA_ValueTreeNode *node; unsigned int allocateEmptyString; TA_Libc *libHandle; TA_StringCache *stringCache; libHandle = data->libHandle; TA_TRACE_BEGIN( libHandle, TA_FileIndexAddTreeValue ); stringCache = TA_GetGlobalStringCache( libHandle ); allocateEmptyString = 0; TA_ASSERT( libHandle, data != NULL ); if( added ) *added = NULL; if( !string ) { string = TA_StringAlloc( stringCache, "" ); if( !string ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } allocateEmptyString = 1; } /* Alloc the TA_ValueTreeNode */ node = allocTreeNode( libHandle, data->currentNode, string ); if( allocateEmptyString ) TA_StringFree( stringCache, string ); if( !node ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } data->currentNode = node; if( added ) *added = node; TA_TRACE_RETURN( TA_SUCCESS ); }
static TA_RetCode TA_SystemGlobalInit( void **globalToAlloc ) { TA_PROLOG TA_RetCode retCode; TA_SystemGlobal *global; TA_TRACE_BEGIN( TA_SystemGlobalInit ); TA_ASSERT( globalToAlloc != NULL ); *globalToAlloc = NULL; global = (TA_SystemGlobal *)TA_Malloc( sizeof( TA_SystemGlobal ) ); if( !global ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } memset( global, 0, sizeof( TA_SystemGlobal ) ); retCode = TA_StringCacheAlloc( &global->dirnameCache ); if( retCode != TA_SUCCESS ) { TA_Free( global ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } retCode = TA_StringCacheAlloc( &global->filenameCache ); if( retCode != TA_SUCCESS ) { TA_StringCacheFree( global->dirnameCache ); TA_Free( global ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } /* Success! Return the global to the caller. */ *globalToAlloc = global; TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_FileIndexFreeValueTree( TA_Libc *libHandle, TA_ValueTreeNode *fromNode ) { TA_PROLOG; TA_RetCode retCode; TA_ValueTreeNode *tmp; TA_StringCache *stringCache; TA_TRACE_BEGIN( libHandle, TA_FileIndexFreeValueTree ); TA_ASSERT( libHandle, fromNode != NULL ); stringCache = TA_GetGlobalStringCache( libHandle ); /* Remove itself from parent->child list if parent still around. */ if( fromNode->parent ) { tmp = ((TA_ValueTreeNode *)fromNode->parent); if( tmp->child ) TA_ListRemoveEntry( tmp->child, (void *)fromNode ); } if( fromNode->string ) TA_StringFree( stringCache, fromNode->string ); /* Deletes all childs. */ if( fromNode->child ) { retCode = freeListAndElement( libHandle, fromNode->child, freeTreeNode ); if( retCode != TA_SUCCESS ) TA_TRACE_RETURN( retCode ); } TA_Free( libHandle, fromNode ); TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_ReadOp_Do( TA_FileHandle *fileHandle, const TA_ReadOpInfo *readOpInfo, TA_Period period, const TA_Timestamp *start, const TA_Timestamp *end, unsigned int minimumNbBar, TA_Field fieldToAlloc, TA_ParamForAddData *paramForAddData, unsigned int *nbBarAdded ) { TA_PROLOG TA_RetCode retCode; TA_EstimateInfo estimationInfo; unsigned int nbElementToAllocate; unsigned int memoryNeeded; /* Boolean */ unsigned int timeNeeded; /* Boolean */ TA_Real *arrayReal[TA_REAL_ARRAY_SIZE]; TA_Integer *arrayInteger[TA_INTEGER_ARRAY_SIZE]; TA_Timestamp *timestamp; TA_Real *openBeg, *highBeg, *lowBeg, *closeBeg; TA_Integer *volumeBeg, *openInterestBeg; TA_Timestamp *timestampBeg; TA_Timestamp tmpTimestamp; TA_ReadOp op; TA_Field fieldToProcess; unsigned int year, month, day, hour, min, sec; TA_Integer curOp; unsigned int nbTotalByteDone, nbTotalBarDone; unsigned int nbBarAddedInTheBlock; char monthChar[4]; char cnvtArray[CNVT_ARRAY_SIZE]; unsigned int cnvtArrayIdx; unsigned int nbByteToAllocReal; unsigned int nbByteToAllocInteger; unsigned int fileSize; unsigned int skipField; unsigned int lineToSkip; unsigned int nbByteRead; unsigned int nbLetter; TA_Real lastValidClose; const char *car; register TA_Real tmpReal; register TA_Integer tmpInt; register unsigned int tmpIdx; register unsigned int nbCharToRead; unsigned int lastOpFieldIncremented; TA_TRACE_BEGIN( TA_PriceBarRead ); /* Initialization of local variables. */ openBeg = highBeg = lowBeg = closeBeg = NULL; timestampBeg = NULL; volumeBeg = openInterestBeg = NULL; timestamp = NULL; retCode = TA_SUCCESS; lastValidClose = 0.0; fieldToProcess = readOpInfo->fieldProvided & fieldToAlloc; if( (fieldToProcess & fieldToAlloc) != fieldToAlloc ) { /* Nothing to read because not all the requested * fields are provided by this data source! */ return TA_SUCCESS; } /* Estimate the initial amount of memory to allocate. */ fileSize = TA_FileSize( fileHandle ); retCode = TA_EstimateAllocInit( start, end, period, minimumNbBar, 2048, &estimationInfo, &nbElementToAllocate ); if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } if( nbElementToAllocate == 0 ) { TA_TRACE_RETURN( TA_SUCCESS ); /* Nothing to read!? Just return... */ } memset( arrayInteger, 0, sizeof( arrayInteger ) ); memset( arrayReal, 0, sizeof( arrayReal ) ); /* Set the date/time pointers to where the information will be stored. */ arrayInteger[TA_HOUR_IDX] = (TA_Integer *)&hour; arrayInteger[TA_MIN_IDX] = (TA_Integer *)&min; arrayInteger[TA_SEC_IDX] = (TA_Integer *)&sec; arrayInteger[TA_MONTH_IDX] = (TA_Integer *)&month; arrayInteger[TA_YEAR_IDX] = (TA_Integer *)&year; arrayInteger[TA_DAY_IDX] = (TA_Integer *)&day; /* Set default time/date. */ year = 1900; month = day = 1; hour = 23; min = sec = 59; /* Check if the processing of the time will be needed. */ timeNeeded = isTimeNeeded( readOpInfo->arrayReadOp); /* 'car' always point to the character being currently handled. */ nbByteRead = 0; car = TA_FileSeqRead( fileHandle, &nbByteRead ); if( (car == NULL) || (nbByteRead == 0) ) return TA_SUCCESS; /* End of file! */ --nbByteRead; nbTotalByteDone = 0; nbTotalBarDone = 0; nbBarAddedInTheBlock = 0; memoryNeeded = 1; curOp = 0; skipField = 0; monthChar[3] = '\0'; /* When requested, skip header lines. */ lineToSkip = readOpInfo->nbHeaderLineToSkip; while( lineToSkip-- ) { while( *car != '\n' ) { GET_CHAR; if( car == NULL ) goto exit_loops; } } line_loop: /* Always jump here when end-of-line is found (EOL). */ /* If curOp != 0, the last operations are canceled. */ REVERT_OPERATIONS; curOp = 0; lastOpFieldIncremented = 0; /* Start over a new line. */ if( memoryNeeded ) { /* Allocate the memory. */ nbByteToAllocReal = nbElementToAllocate * sizeof( TA_Real ); nbByteToAllocInteger = nbElementToAllocate * sizeof( TA_Integer ); timestamp = (TA_Timestamp *)TA_Malloc( nbElementToAllocate * sizeof( TA_Timestamp ) ); timestampBeg = timestamp; if( !timestampBeg ) { retCode = TA_ALLOC_ERR; goto exit_loops; } #define TA_ALLOC_MEM(upperc,lowerc,typepar) \ { \ if( fieldToProcess & TA_##upperc ) \ { \ lowerc##Beg = (TA_##typepar *)TA_Malloc( nbByteToAlloc##typepar ); \ array##typepar[TA_##upperc##_IDX] = lowerc##Beg; \ if( !lowerc##Beg ) \ { \ retCode = TA_ALLOC_ERR; \ goto exit_loops; \ } \ } \ } TA_ALLOC_MEM( OPEN, open, Real ); TA_ALLOC_MEM( HIGH, high, Real ); TA_ALLOC_MEM( LOW, low, Real ); TA_ALLOC_MEM( CLOSE, close, Real ); TA_ALLOC_MEM( VOLUME, volume, Integer ); TA_ALLOC_MEM( OPENINTEREST, openInterest, Integer ); #undef TA_ALLOC_MEM memoryNeeded = 0; } op_loop: /* Jump here when ready to proceed with the next command. */ op = readOpInfo->arrayReadOp[curOp]; if( !(op&TA_CMD_READ_MONTH_CHAR) ) { /* Skip leading non-numeric character. */ SKIP_UNTIL_NUMERIC; } /* Shall we skip this field? */ if( TA_IS_SKIP_SET(op) ) { if( (op&(TA_CMD_READ_REAL|TA_CMD_READ_INTEGER)) == 0 ) { tmpInt = TA_GET_NB_NUMERIC(op); curOp++; while( tmpInt-- ) { GET_CHAR; CHECK_EOL_EOF; } } else { if( skipField == 0 ) { skipField = TA_GET_NB_NUMERIC(op); TA_ASSERT( skipField > 0 ); } if( --skipField == 0 ) curOp++; SKIP_NUMERIC; if( (op&TA_CMD_READ_REAL) && (*car == '.') ) { GET_CHAR; CHECK_EOL_EOF; SKIP_NUMERIC; } } } else { cnvtArrayIdx = 0; if( TA_IS_REAL_CMD(op) ) { /* Extract a numeric into cnvtArray. */ READ_IN_CNVT_ARRAY; /* This is a TA_Real. */ if( car && (*car == '.') ) { /* Read rest of the float after the '.' */ READ_IN_CNVT_ARRAY; } cnvtArray[cnvtArrayIdx] = '\0'; tmpReal = atof( &cnvtArray[0] ); /* Write the TA_Real in memory. */ tmpIdx = TA_GET_IDX(op); TA_ASSERT( tmpIdx < TA_REAL_ARRAY_SIZE ); TA_ASSERT( arrayReal[tmpIdx] != NULL ); if( tmpReal != 0.0 ) { *(arrayReal[tmpIdx]) = tmpReal; if( tmpIdx == TA_CLOSE_IDX ) lastValidClose = tmpReal; } else if( TA_IS_REPLACE_ZERO(op) ) { /* Replace this zero value with the last known close. * If there is no previous close, this line is ignored. */ if( lastValidClose != 0.0 ) *(arrayReal[tmpIdx]) = lastValidClose; else { SKIP_LINE; } } else { /* Zero are not expected, consider this as a failure * and ignore all further data from this file. */ retCode = TA_PRICE_BAR_CONTAINS_ZERO; goto exit_loops; } arrayReal[tmpIdx]++; curOp++; } else { /* This is a TA_Integer. */ if( !(op&TA_CMD_READ_MONTH_CHAR) ) { nbCharToRead = TA_GET_NB_NUMERIC(op); if( nbCharToRead ) { READ_N_CHAR_IN_CNVT_ARRAY(nbCharToRead); } else { READ_IN_CNVT_ARRAY; } cnvtArray[cnvtArrayIdx] = '\0'; tmpInt = atoi( &cnvtArray[0] ); } else { /* Try to find a 3 letters month string. * Translate it to a [1..12] integer. */ nbLetter = 1; do { CHECK_EOL_EOF; monthChar[nbLetter] = (char)toupper(*car); GET_CHAR; nbLetter++; } while( nbLetter != 3 ); do { CHECK_EOL_EOF; monthChar[0] = monthChar[1]; monthChar[1] = monthChar[2]; monthChar[2] = (char)toupper(*car); if( strncmp("JAN",monthChar,3) == 0 ) tmpInt = 1; else if( strncmp("FEB",monthChar,3) == 0 ) tmpInt = 2; else if( strncmp("MAR",monthChar,3) == 0 ) tmpInt = 3; else if( strncmp("APR",monthChar,3) == 0 ) tmpInt = 4; else if( strncmp("MAY",monthChar,3) == 0 ) tmpInt = 5; else if( strncmp("JUN",monthChar,3) == 0 ) tmpInt = 6; else if( strncmp("JUL",monthChar,3) == 0 ) tmpInt = 7; else if( strncmp("AUG",monthChar,3) == 0 ) tmpInt = 8; else if( strncmp("SEP",monthChar,3) == 0 ) tmpInt = 9; else if( strncmp("OCT",monthChar,3) == 0 ) tmpInt = 10; else if( strncmp("NOV",monthChar,3) == 0 ) tmpInt = 11; else if( strncmp("DEC",monthChar,3) == 0 ) tmpInt = 12; else tmpInt = 0; GET_CHAR; } while( tmpInt == 0 ); } /* Write the TA_Integer in memory. */ tmpIdx = TA_GET_IDX(op); TA_ASSERT( tmpIdx < TA_INTEGER_ARRAY_SIZE ); TA_ASSERT( arrayInteger[tmpIdx] != NULL ); *(arrayInteger[tmpIdx]) = tmpInt; if( tmpIdx > TA_YEAR_IDX ) arrayInteger[tmpIdx]++; curOp++; if( TA_IS_TIMESTAMP_COMPLETE(op) ) { /* Build the timestamp. */ retCode = TA_SetDate( year, month, day, &tmpTimestamp ); if( retCode != TA_SUCCESS ) goto exit_loops; /* Invalid date */ if( !timeNeeded ) { /* Ignore time in comparison and use default to build the price bar. */ tmpTimestamp.time = 23595900; /* Default EOD time */ if( start && (tmpTimestamp.date < start->date) ) { /* This price bar is not needed, jump to the next line. */ retCode = TA_SUCCESS; SKIP_LINE; } if( end && (tmpTimestamp.date > end->date) ) { /* This price bar is beyond the upper limit, just exit. */ goto exit_loops; } } else { retCode = TA_SetTime( hour, min, sec, &tmpTimestamp ); if( retCode != TA_SUCCESS ) goto exit_loops; /* Invalid time */ if( start && TA_TimestampLess(&tmpTimestamp,start) ) { /* This price bar is not needed, jump to the next line. */ retCode = TA_SUCCESS; SKIP_LINE; } if( end && TA_TimestampGreater(&tmpTimestamp, end) ) { /* This price bar is beyond the upper limit, just exit. */ goto exit_loops; } } /* Write the timestamp in memory. */ *timestamp = tmpTimestamp; } } if( TA_IS_READ_STOP_FLAG_SET(op) ) { #ifdef DEBUG_PRINTF printf( "(%d%d%d,%e,%e,%e,%e,%d)\n", timestampBeg?TA_GetYear(×tampBeg[nbBarAddedInTheBlock]):0, timestampBeg?TA_GetMonth(×tampBeg[nbBarAddedInTheBlock]):0, timestampBeg?TA_GetDay(×tampBeg[nbBarAddedInTheBlock]):0, openBeg?openBeg[nbBarAddedInTheBlock]:0.0, highBeg?highBeg[nbBarAddedInTheBlock]:0.0, lowBeg?lowBeg[nbBarAddedInTheBlock]:0.0, closeBeg?closeBeg[nbBarAddedInTheBlock]:0.0, volumeBeg?volumeBeg[nbBarAddedInTheBlock]:0 ); #endif /* At this point, the price bar is completely written in memory. */ timestamp++; curOp = 0; nbBarAddedInTheBlock++; if( nbBarAddedInTheBlock < nbElementToAllocate ) { /* Go to next line. */ SKIP_LINE; } else { /* There is not enough memory for another bar, so re-allocate * some more. */ retCode = TA_HistoryAddData( paramForAddData, nbBarAddedInTheBlock, period, timestampBeg, openBeg, highBeg, lowBeg, closeBeg, volumeBeg, openInterestBeg ); /* TA_HistoryAddData is ALWAYS the owner of these memory block * when called. So we set these to NULL to make sure there will * be no attempt to free these from this function. */ openBeg = highBeg = lowBeg = closeBeg = NULL; timestampBeg = NULL; volumeBeg = openInterestBeg = NULL; nbTotalBarDone += nbBarAddedInTheBlock; nbBarAddedInTheBlock = 0; if( retCode != TA_SUCCESS ) goto exit_loops; retCode = TA_EstimateAllocNext( &estimationInfo, &nbElementToAllocate ); if( retCode != TA_SUCCESS ) goto exit_loops; memoryNeeded = 1; SKIP_LINE; } } else { /* Make sure we did not hit an EOL or EOF prematurly, if yes, * this line will be silently ignored. */ CHECK_EOL_EOF; } } goto op_loop; exit_loops: /* Jump here when the end-of-file is hit (or an error occured) */ /* On succesful exit, process possibly remaining data. */ if( (retCode == TA_SUCCESS) && (nbBarAddedInTheBlock != 0) ) { retCode = TA_HistoryAddData( paramForAddData, nbBarAddedInTheBlock, period, timestampBeg, openBeg, highBeg, lowBeg, closeBeg, volumeBeg, openInterestBeg ); openBeg = highBeg = lowBeg = closeBeg = NULL; timestampBeg = NULL; volumeBeg = openInterestBeg = NULL; nbTotalBarDone += nbBarAddedInTheBlock; } /* ALWAYS verify if locally allocated memory needs to be freed. ALWAYS. */ FREE_IF_NOT_NULL( openBeg ); FREE_IF_NOT_NULL( highBeg ); FREE_IF_NOT_NULL( lowBeg ); FREE_IF_NOT_NULL( closeBeg ); FREE_IF_NOT_NULL( volumeBeg ); FREE_IF_NOT_NULL( openInterestBeg ); FREE_IF_NOT_NULL( timestampBeg ); /* An indication that no more data needs to be provided is not a failure. */ if( retCode == TA_ENOUGH_DATA ) retCode = TA_SUCCESS; /* Return the number of added price bar to the caller. */ if( nbBarAdded ) *nbBarAdded = nbTotalBarDone; TA_TRACE_RETURN( retCode ); }
/**** Global functions definitions. ****/ TA_RetCode TA_GetHistoryDataFromWeb( TA_Libc *libHandle, TA_DataSourceHandle *handle, TA_CategoryHandle *categoryHandle, TA_SymbolHandle *symbolHandle, TA_Period period, const TA_Timestamp *start, const TA_Timestamp *end, TA_Field fieldToAlloc, TA_ParamForAddData *paramForAddData ) { TA_PROLOG; TA_RetCode retCode; TA_StringCache *stringCache; TA_String *yahooName; TA_WebPage *webPage; TA_PrivateYahooHandle *yahooHandle; TA_DecodingParam localDecodingParam; const TA_DecodingParam *decodingParam; TA_FileHandle *fileHandle; TA_ReadOpInfo *readOpInfo; UIRSuffixParsing suffixParsing; TA_Timestamp firstBarTimestamp, lastBarTimestamp, prevEndDate; TA_InfoFromAddedData infoFromAddedData; TA_DayOfWeek dayOfWeek; int nbEstimateBar; int nbField; unsigned int nbBarAdded, nbTotalBarAdded; int again, firstTime, nbBatch; int zeroBarAddedAttempt; TA_TRACE_BEGIN( libHandle, TA_GetHistoryDataFromWeb ); /* Initialize some local variables. */ stringCache = TA_GetGlobalStringCache( libHandle ); yahooHandle = (TA_PrivateYahooHandle *)handle->opaqueData; readOpInfo = NULL; nbEstimateBar = 0; TA_ASSERT( libHandle, categoryHandle != NULL ); TA_ASSERT( libHandle, symbolHandle != NULL ); TA_ASSERT( libHandle, categoryHandle->string != NULL ); TA_ASSERT( libHandle, symbolHandle->string != NULL ); /* Set the initial first/last timestamp */ if( start ) TA_TimestampCopy( &firstBarTimestamp, start ); else { TA_SetDate( 1950, 1, 1, &firstBarTimestamp ); TA_SetTime( 0, 0, 0, &firstBarTimestamp ); } if( end ) TA_TimestampCopy( &lastBarTimestamp, end ); else { TA_SetDateNow( &lastBarTimestamp ); TA_SetTime( 0, 0, 0, &lastBarTimestamp ); } /* Make sure that lastBarTimestamp is a week-day. */ dayOfWeek = TA_GetDayOfTheWeek( &lastBarTimestamp ); if( (dayOfWeek == TA_SUNDAY) || (dayOfWeek == TA_SATURDAY) ) TA_PrevWeekday( &lastBarTimestamp ); /* Map the TA-Lib name into the Yahoo! name. */ retCode = TA_AllocStringFromLibName( libHandle, categoryHandle->string, symbolHandle->string, &yahooName ); if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } TA_ASSERT( libHandle, yahooName != NULL ); TA_ASSERT( libHandle, yahooHandle != NULL ); /* Get the decoding parameter for the CSV web page. */ decodingParam = TA_YahooIdxDecodingParam( yahooHandle->index, TA_YAHOOIDX_CVS_PAGE ); if( !decodingParam ) { TA_StringFree( stringCache, yahooName ); TA_TRACE_RETURN( TA_INTERNAL_ERROR(103) ); } /* Use a local copy of the decoding param. * This is because the uirSuffix is replaced with * an allocated buffer (so the date field can be * manipulated). */ localDecodingParam = *decodingParam; /* Parse the uirSuffix so the start/end date can be changed. */ if( !setUIRSuffixParsing( decodingParam->uirSuffix, &suffixParsing ) ) { /* This should never happen unless the * Yahoo! index protocol has been broken. */ /* Clean-up and exit */ TA_StringFree( stringCache, yahooName ); TA_TRACE_RETURN( TA_INTERNAL_ERROR(104) ); } /* Replace the uirSuffix with a large local buffer. */ localDecodingParam.uirSuffix = TA_Malloc( libHandle, suffixParsing.maxTotalLength ); if( !localDecodingParam.uirSuffix ) { /* Clean-up and exit */ TA_StringFree( stringCache, yahooName ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } /* Change the dates in the uirSuffix. */ buildUIRSuffix( &suffixParsing, &firstBarTimestamp, &lastBarTimestamp, (char *)localDecodingParam.uirSuffix ); /* nbBatch is a safety net to make sure that * TA-Lib won't stay forever in the while loop * in case Yahoo! changes their protocol. */ nbBatch = 0; /* Sometime Yahoo! return an empty csv file. Make * multiple attempts in that case. */ zeroBarAddedAttempt = 0; again = 1; firstTime = 1; nbTotalBarAdded = 0; while( again && (++nbBatch < 100) && (zeroBarAddedAttempt < 10) ) { if( TA_TimestampLess(&lastBarTimestamp,&firstBarTimestamp) ) { /* Get out of this loop if all the requested data * has been retreived already. */ again = 0; break; } retCode = TA_WebPageAllocFromYahooName( libHandle, &localDecodingParam, TA_StringToChar(yahooName), &webPage ); if( retCode != TA_SUCCESS ) { TA_StringFree( stringCache, yahooName ); TA_Free( libHandle, (char *)localDecodingParam.uirSuffix ); TA_TRACE_RETURN( retCode ); } /* Disguise the webPage stream into a "file". That way the speed * optimized ASCII decoder can be re-used (TA_ReadOp stuff). */ retCode = TA_FileSeqOpenFromStream( libHandle, webPage->content, &fileHandle ); if( retCode != TA_SUCCESS ) { /* Clean-up and exit */ TA_StringFree( stringCache, yahooName ); TA_WebPageFree( webPage ); TA_Free( libHandle, (char *)localDecodingParam.uirSuffix ); TA_TRACE_RETURN( retCode ); } if( firstTime ) { /* Make assumption of the data provided * base on the number of fields in the CSV file. */ nbField = nbCommaField( webPage->content ); switch( nbField ) { case 2: readOpInfo = yahooHandle->readOp2Fields; break; case 5: readOpInfo = yahooHandle->readOp5Fields; break; default: readOpInfo = yahooHandle->readOp6Fields; } /* User asking for all the fields? */ if( fieldToAlloc == TA_ALL ) { switch( nbField ) { case 2: fieldToAlloc = TA_CLOSE|TA_TIMESTAMP; break; case 5: fieldToAlloc = TA_OPEN|TA_HIGH|TA_LOW|TA_CLOSE|TA_TIMESTAMP; break; default: fieldToAlloc = TA_OPEN|TA_HIGH|TA_LOW|TA_CLOSE|TA_VOLUME|TA_TIMESTAMP; } } /* Optimize the read op for the requested data. */ retCode = TA_ReadOp_Optimize( libHandle, readOpInfo, period, fieldToAlloc ); if( retCode != TA_SUCCESS ) { /* Clean-up and exit */ TA_StringFree( stringCache, yahooName ); TA_WebPageFree( webPage ); TA_Free( libHandle, (char *)localDecodingParam.uirSuffix ); TA_TRACE_RETURN( retCode ); } /* Make an estimation of the number of price bar. */ nbEstimateBar = TA_StreamCountChar( webPage->content, '\n' ) + 1; if( nbEstimateBar < 100 ) nbEstimateBar = 100; } /* Interpret the CSV data. */ retCode = TA_ReadOp_Do( libHandle, fileHandle, readOpInfo, period, &firstBarTimestamp, &lastBarTimestamp, nbEstimateBar, fieldToAlloc, paramForAddData, &nbBarAdded ); TA_FileSeqClose( libHandle, fileHandle ); TA_WebPageFree( webPage ); nbTotalBarAdded += nbBarAdded; if( retCode != TA_SUCCESS ) { /* Clean-up and exit */ TA_StringFree( stringCache, yahooName ); TA_Free( libHandle, (char *)localDecodingParam.uirSuffix ); TA_TRACE_RETURN( retCode ); } /* Yahoo! does not always return all the data it could, up to * the requested end date. It is important to detect these occurence * and cancel the usage of all data accumulated up to now. */ TA_GetInfoFromAddedData( paramForAddData, &infoFromAddedData ); if( infoFromAddedData.barAddedSinceLastCall ) { /* Do some more checking by considering holidays, week-end etc... */ if( !isGapAcceptable(&infoFromAddedData.highestTimestampAddedSinceLastCall, &lastBarTimestamp) ) { /* Clean-up and exit */ TA_StringFree( stringCache, yahooName ); TA_Free( libHandle, (char *)localDecodingParam.uirSuffix ); TA_TRACE_RETURN( TA_DATA_GAP ); } TA_TimestampCopy( &lastBarTimestamp, &infoFromAddedData.lowestTimestamp ); } #if DEBUG_PRINTF printf( "NB BAR ADDED=%d, TOTAL=%d\n", nbBarAdded, nbTotalBarAdded ); #endif /* Verify if more data should be processed. * Yahoo! sometimes slice their data, in * batch of 200 price bars. */ if( firstTime && (nbBarAdded > 200) ) { again = 0; /* Assume all the data extracted... exit the loop. */ } else if( nbBarAdded == 0 ) { /* Make multiple attempts when retreiving data succeed, * but somehow there is zero bar returned. * * Sometimes this might be correct when there is truly no * more data available, so choosing an algorithm before * giving up is a comprimise between reliability and * usability. The data source is free... and you get * what you pay for after all ;) */ if( (nbTotalBarAdded < 1000) && (zeroBarAddedAttempt >= 1) && (zeroBarAddedAttempt < 7) ) { /* I did choose to add a delay when insufficient total data is returned. When * there is already ~5 years of data, most likely there is "Zero" returned * because there is NO more data available, so just do the retry without delay. */ TA_Sleep(zeroBarAddedAttempt*2); } #if DEBUG_PRINTF printf( "Retry %d", zeroBarAddedAttempt ); #endif zeroBarAddedAttempt++; } else { zeroBarAddedAttempt = 0; if( TA_TimestampEqual( &lastBarTimestamp, &prevEndDate ) ) { /* prevEndDate is a "safety net" to * exit the loop early in case Yahoo! starts * to return always the same batch of data. * Just ignore the repetitive data and exit. */ TA_Free( libHandle, (char *)localDecodingParam.uirSuffix ); TA_StringFree( stringCache, yahooName ); TA_TRACE_RETURN( TA_SUCCESS ); } TA_TimestampCopy( &prevEndDate, &lastBarTimestamp ); /* Request the data up to the day BEFORE * the last batch of data received. */ TA_PrevDay( &lastBarTimestamp ); /* Make sure that lastBarTimestamp is a week-day. */ dayOfWeek = TA_GetDayOfTheWeek( &lastBarTimestamp ); if( (dayOfWeek == TA_SUNDAY) || (dayOfWeek == TA_SATURDAY) ) TA_PrevWeekday( &lastBarTimestamp ); /* Change the dates in the uirSuffix. */ buildUIRSuffix( &suffixParsing, &firstBarTimestamp, &lastBarTimestamp, (char *)localDecodingParam.uirSuffix ); /* From that point, data is expected to be most likely * sent in batch of 200. */ nbEstimateBar = 200; } firstTime = 0; } /* Clean-up and exit */ TA_Free( libHandle, (char *)localDecodingParam.uirSuffix ); TA_StringFree( stringCache, yahooName ); TA_TRACE_RETURN( retCode ); }
static TA_RetCode equityPeriodTransform( TA_PMPriv *pmPriv, TA_Period newPeriod, /* The new desired period. */ unsigned int *nbBars, /* Return the number of price bar */ TA_Timestamp **timestamp, /* Allocate new timestamp. */ TA_Real **equity ) /* Allocate new equity. */ { TA_PROLOG /* Notice that this function is very similar to the * TA_PeriodTransform function in ta_period.c * * If you find a bug here, may be worth double * checking TA_PeriodTransform as well... */ TA_RetCode retCode; /* Temporaries. */ const TA_Timestamp *tempTimestamp; unsigned int tempInt, tempInt2; /* Variable used to identify period crossing. */ unsigned int currentWeek, currentMonth, currentYear, currentQuarter; /* Pointer on the history being transformed. */ const TA_Timestamp *old_timestamp; const TA_Real *old_equity; TA_Integer old_nbBars; /* Pointer on the transformed data. */ TA_Timestamp *new_timestamp; /* New allocated timestamp. */ TA_Real *new_equity; /* New allocated open. */ TA_Integer new_nbBars; TA_Timestamp cur_timestamp; /* Current new timestamp of new period. */ TA_Real cur_equity; /* Current new equity of new period. */ int oldPriceBar, newPriceBar; /* Array iterators. */ unsigned int again, periodCompleted; /* Boolean */ int firstIteration; TA_TRACE_BEGIN( TA_PeriodTransform ); /* Validate some mandatory parameter. */ TA_ASSERT( newPeriod != 0 ); TA_ASSERT( nbBars != NULL ); /* It is assume that the caller call this function * when there is really a transform to do. */ TA_ASSERT( newPeriod != TA_DAILY ); /* Of course, timestamps from the source are needed. */ TA_ASSERT( pmPriv->arrayTimestamp != NULL ); /* Initialize all callers pointers to NULL. * These will be initialize only on success. * In the meantime, new_XXXX pointers are * going to be used on the new allocated data. */ if( !timestamp || !equity ) return TA_BAD_PARAM; *timestamp = NULL; *equity = NULL; *nbBars = 0; /* Validate the supported transformation. */ /* Eliminate all the transform that * are currently not supported. * Identify also the major steps * needed to perform the transformation. */ switch( newPeriod ) { case TA_WEEKLY: case TA_MONTHLY: case TA_QUARTERLY: case TA_YEARLY: /* These are supported. */ break; default: TA_TRACE_RETURN( TA_PERIOD_NOT_AVAILABLE ); } /* OK.. now proceed with the transformations. * The strategy is simple: * The equity for the whole period will be the * equity at the last daily price bar of * that period. */ old_timestamp = &pmPriv->arrayTimestamp[0]; old_equity = &pmPriv->equity[0]; old_nbBars = pmPriv->nbDailyBars; new_timestamp = NULL; newPriceBar = 0; cur_timestamp.date = 0; /* Current new timestamp of new period. */ cur_timestamp.time = 0; /* Current new timestamp of new period. */ /* Overestimate the number of required new price bar. */ switch( newPeriod ) { case TA_WEEKLY: retCode = TA_TimestampDeltaWeek( &old_timestamp[0], &old_timestamp[old_nbBars-1], (unsigned int *)&new_nbBars ); break; case TA_MONTHLY: retCode = TA_TimestampDeltaMonth( &old_timestamp[0], &old_timestamp[old_nbBars-1], (unsigned int *)&new_nbBars ); break; case TA_QUARTERLY: retCode = TA_TimestampDeltaQuarter( &old_timestamp[0], &old_timestamp[old_nbBars-1], (unsigned int *)&new_nbBars ); break; case TA_YEARLY: retCode = TA_TimestampDeltaYear( &old_timestamp[0], &old_timestamp[old_nbBars-1], (unsigned int *)&new_nbBars ); break; default: TA_TRACE_RETURN( TA_INTERNAL_ERROR(126) ); } if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } new_nbBars += 2; /* To be on the safe side */ /* Allocate the new data. */ new_timestamp = TA_Malloc( new_nbBars * sizeof( TA_Timestamp ) ); if( !new_timestamp ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } new_equity = TA_Malloc( new_nbBars * sizeof( TA_Real ) ); if( !new_equity ) { TA_Free( new_timestamp ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } /* Allows to detect crossing of the new period. */ currentYear = TA_GetYear ( &old_timestamp[0] ); currentMonth = TA_GetMonth( &old_timestamp[0] ); currentWeek = TA_GetWeekOfTheYear( &old_timestamp[0] ); currentQuarter = TA_GetQuarterOfTheYear( &old_timestamp[0] ); /* Iterate through the old price bar. */ oldPriceBar = 0; /* Iterate through the new price bar. */ newPriceBar = 0; again = 1; /* Becomes false when all bars are processed. */ while( again ) { /* Initialize cur_XXXXXX variables with the first bar in old timeframe. */ cur_timestamp = old_timestamp[oldPriceBar]; cur_equity = old_equity [oldPriceBar]; /* Go through the bars and accumulate the info * until the end of the requested period is reach. */ periodCompleted = 0; firstIteration = 1; while( (oldPriceBar < old_nbBars) && !periodCompleted ) { tempTimestamp = &old_timestamp[oldPriceBar]; /* Check if we reached an end of period. */ switch( newPeriod ) { case TA_WEEKLY: tempInt = TA_GetWeekOfTheYear( tempTimestamp ); /* Trap weeks on years boundary. */ if( (currentWeek == 52) && (tempInt == 0) ) currentWeek = 0; else if( currentWeek != tempInt ) { periodCompleted = 1; currentWeek = tempInt; } break; case TA_MONTHLY: tempInt = TA_GetMonth( tempTimestamp ); tempInt2 = TA_GetYear(tempTimestamp); if( (currentMonth != tempInt) || (currentYear != tempInt2) ) { periodCompleted = 1; currentMonth = tempInt; currentYear = tempInt2; } break; case TA_QUARTERLY: tempInt = TA_GetQuarterOfTheYear( tempTimestamp ); tempInt2 = TA_GetYear(tempTimestamp); if( (currentQuarter != tempInt) || (currentYear != tempInt2) ) { periodCompleted = 1; currentQuarter = tempInt; currentYear = tempInt2; } break; case TA_YEARLY: tempInt = TA_GetYear( tempTimestamp ); if( currentYear != tempInt ) { periodCompleted = 1; currentYear = tempInt; } break; default: /* Do nothing */ break; } /* If this is not the end of a period (in the new timeframe) * just accumulate the data. If this is the end of the period * that while loop will be exited. * Nothing is done on the first iteration because all the * cur_XXXX variables have been already initialized. */ if( !periodCompleted ) { if( !firstIteration ) { /* Adjust the new price bar. */ cur_timestamp = old_timestamp[oldPriceBar]; cur_equity = old_equity [oldPriceBar]; } else firstIteration = 0; /* Move to next bar. */ oldPriceBar++; } } /* We got all the info needed in the cur_XXXXX variables for * proceeding with the initialization of the new period price bar. */ TA_DEBUG_ASSERT( newPriceBar < new_nbBars ); /* If the timestamp is requested, some adjustment could be * needed to cur_timestamp. */ switch( newPeriod ) { case TA_WEEKLY: /* Now something a little bit tricky, we must * make sure that this new price bar is reported * as being the Friday of that week (even if there * is no price bar for that Friday). */ TA_JumpToDayOfWeek( &cur_timestamp, TA_FRIDAY ); break; case TA_MONTHLY: /* Monthly timestamp always end with the last day of * the month. Even if there was no actual transaction * the last day. */ TA_JumpToEndOfMonth( &cur_timestamp ); break; case TA_QUARTERLY: /* Quarterly timestamp always end with the last day of * the quarter. Even if there was no actual transaction * the last day. * Quarter 1 = 3/31 * Quarter 2 = 6/30 * Quarter 3 = 9/30 * Quarter 4 = 12/31 */ TA_JumpToEndOfQuarter( &cur_timestamp ); break; case TA_YEARLY: /* Yearly data always end on 12/31. */ TA_JumpToEndOfYear( &cur_timestamp ); break; default: /* Do nothing. */ break; } /* The new price bar is initialized here. */ new_timestamp[newPriceBar] = cur_timestamp; new_equity [newPriceBar] = cur_equity; /* This new period bar is completed, move to the next one. */ newPriceBar++; /* Any more data to process? */ if( oldPriceBar >= old_nbBars) again = 0; /* All bars have been processsed. */ } /* All done! Return the final result to the caller. */ *equity = new_equity; *timestamp = new_timestamp; *nbBars = newPriceBar; TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_FileSeqOpen( const char *path, TA_FileHandle **handle ) { TA_PROLOG TA_FileHandlePriv *fileHandlePriv; TA_TRACE_BEGIN( TA_FileSeqOpen ); TA_ASSERT( path != NULL ); TA_ASSERT( handle != NULL ); fileHandlePriv = (TA_FileHandlePriv *)TA_Malloc( sizeof( TA_FileHandlePriv ) ); if( !fileHandlePriv ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } memset( fileHandlePriv, 0, sizeof( TA_FileHandlePriv ) ); #if defined( USE_WIN32_API ) fileHandlePriv->handle = CreateFile( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if( fileHandlePriv->handle == INVALID_HANDLE_VALUE ) { TA_FileSeqClose( (TA_FileHandle *)fileHandlePriv ); TA_TRACE_RETURN( TA_ACCESS_FAILED ); } #else /* For all non-win32 platform, use standard ANSI C I/O */ fileHandlePriv->handle = fopen( path, "rb" ); if( fileHandlePriv->handle == 0 ) { TA_FileSeqClose( (TA_FileHandle *)fileHandlePriv ); TA_TRACE_RETURN( TA_ACCESS_FAILED ); } #endif /* Allocate buffer memory. */ #if defined( USE_WIN32_API ) fileHandlePriv->allocBuffer = allocDiskBuffer( path, &fileHandlePriv->allocBufferSize ); if( !fileHandlePriv->allocBuffer || (fileHandlePriv->allocBufferSize == 0) ) { TA_FileSeqClose( (TA_FileHandle *)fileHandlePriv ); TA_TRACE_RETURN( TA_ACCESS_FAILED ); } #else fileHandlePriv->allocBuffer = TA_Malloc( FILE_BUFFER_SIZE ); fileHandlePriv->allocBufferSize = FILE_BUFFER_SIZE; if( !fileHandlePriv->allocBuffer ) { TA_FileSeqClose( (TA_FileHandle *)fileHandlePriv ); TA_TRACE_RETURN( TA_ACCESS_FAILED ); } #endif /* Keep a ptr on the path. */ fileHandlePriv->path = path; /* Success! Return the info to the caller. */ *handle = (TA_FileHandle *)fileHandlePriv; TA_TRACE_RETURN( TA_SUCCESS ); }
/**** Global functions definitions. ****/ TA_RetCode TA_ReadOp_Optimize( TA_ReadOpInfo *readOpInfo, TA_Period period, TA_Field fieldToAlloc ) { TA_PROLOG TA_ReadOp *lastOp; unsigned int tmpIdx; unsigned int i, nbReadOp; unsigned int flagSet; TA_Field field; TA_ReadOp *readOp; TA_TRACE_BEGIN( TA_OptimizeReadOp ); TA_ASSERT( fieldToAlloc != 0 ); nbReadOp = readOpInfo->nbReadOp; readOp = readOpInfo->arrayReadOp; /* Skip all fields not requested. */ for( i=0; i < nbReadOp; i++ ) { if( TA_IS_PERMANENT_SKIP_SET(readOp[i]) ) { TA_SET_SKIP_FLAG(readOp[i]); } else { TA_CLR_SKIP_FLAG(readOp[i]); field = TA_ReadOpToField( readOp[i] ); if( field == TA_TIMESTAMP ) { tmpIdx = TA_GET_IDX(readOp[i]); switch( period ) { case TA_YEARLY: /* No need for anything shorter than year in the timestamp. */ if( tmpIdx <= TA_MONTH_IDX ) { TA_SET_SKIP_FLAG(readOp[i]); TA_SET_NB_NUMERIC(readOp[i],1); } break; case TA_MONTHLY: /* No need for anything shorter than days in the timestamp. */ if( tmpIdx <= TA_DAY_IDX ) { TA_SET_SKIP_FLAG(readOp[i]); TA_SET_NB_NUMERIC(readOp[i],1); } break; case TA_DAILY: /* No need for hour,min,sec in the timestamp. */ if( tmpIdx <= TA_HOUR_IDX ) { TA_SET_SKIP_FLAG(readOp[i]); TA_SET_NB_NUMERIC(readOp[i],1); } break; default: /* Do nothing. */ break; } } else if( !(field&fieldToAlloc) ) { /* This field is not requested for being allocated. */ TA_SET_SKIP_FLAG(readOp[i]); TA_SET_NB_NUMERIC(readOp[i],1); } } } TA_ASSERT( TA_IS_LAST_SET(readOp[nbReadOp-1]) ); /* Determine the last needed field. Mark it with the STOP flag. * Make sure all previous get their STOP flag clear. */ flagSet = 0; for( i=nbReadOp; i > 0; i-- ) { lastOp = &readOp[i-1]; if( flagSet ) { TA_CLR_READ_STOP_FLAG(*lastOp); } else { TA_SET_READ_STOP_FLAG(*lastOp); if( !TA_IS_SKIP_SET(*lastOp) ) flagSet = 1; } } TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_ReadOpInfoAlloc( const char *sourceInfo, TA_ReadOpInfo **allocatedInfo, unsigned int readOpFlags ) { TA_PROLOG TA_RetCode retCode; TA_ReadOp readOp; TA_ReadOp *arrayReadOp; TA_ReadOpInfo *newReadOpInfo; TA_Field fieldMask, fieldProvided; unsigned int timeframeIdx; unsigned int intraDayIncPeriod; TA_TokenId intraDayIncToken; TA_TokenId tempToken; unsigned int tempInt; unsigned int period; unsigned int errorOccurred; const char *pos; unsigned int inField; unsigned int nbField; unsigned int nbCharInField; unsigned int skipNonDigitLine; const char *ptrFirstCarInField; unsigned char localBuf[10]; unsigned int bufIdx, opIdx, i; register unsigned int flagSet; register TA_ReadOp *ptrReadOp; TA_TRACE_BEGIN( TA_BuildArrayReadOp ); newReadOpInfo = (TA_ReadOpInfo *)TA_Malloc( sizeof( TA_ReadOpInfo ) ); /* These variables are resolved within this function. */ memset( newReadOpInfo, 0, sizeof( TA_ReadOpInfo ) ); /* At this point, TA_ReadOpInfoFree can be safely called. */ /* Keep track of some user provided parameter. */ newReadOpInfo->sourceInfo = sourceInfo; newReadOpInfo->readOpFlags = readOpFlags; /* Initialize some defaults. */ newReadOpInfo->openInterestMult = 100; newReadOpInfo->volumeMult = 100; nbField = 0; intraDayIncPeriod = 0; intraDayIncToken = TA_TOK_END; pos = newReadOpInfo->sourceInfo; if( !pos || (*pos == '\0') ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_MISSING_FIELD ); } /* Find how many fields are defined and check some syntax * at the same time. */ if( *pos != '[' ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } inField = 0; nbCharInField = 0; skipNonDigitLine = 0; ptrFirstCarInField = NULL; while( *pos != '\0' ) { switch( *pos ) { case '[': if( inField ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } inField = 1; break; case ']': if( (!inField) || (nbCharInField == 0) ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } nbField++; /* Exclude fields not generating a TA_ReadOp. * For the time being that means only the -H and -NDL field. */ if( nbCharInField >= 2 ) { TA_ASSERT( ptrFirstCarInField != NULL ); if( ptrFirstCarInField[0] == '-' ) { if( toupper(ptrFirstCarInField[1]) == 'H' ) nbField--; else if( (toupper(ptrFirstCarInField[1]) == 'N') && (toupper(ptrFirstCarInField[2]) == 'D') && (toupper(ptrFirstCarInField[3]) == 'L') ) { skipNonDigitLine = 1; nbField--; } } } inField = 0; nbCharInField = 0; ptrFirstCarInField = NULL; break; default: if( !inField ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } if( nbCharInField == 0 ) ptrFirstCarInField = pos; nbCharInField++; break; } pos++; } if( inField || *(pos-1) != ']' ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } /* Build the TA_ReadOp array */ arrayReadOp = (TA_ReadOp *)TA_Malloc( sizeof( TA_ReadOp ) * nbField ); if( !arrayReadOp ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } newReadOpInfo->arrayReadOp = arrayReadOp; pos = TA_StringToChar(newReadOpInfo->sourceInfo); bufIdx = 0; opIdx = 0; while( *pos != '\0' && (opIdx < nbField) ) { switch( *pos ) { case '[': break; case ']': localBuf[bufIdx] ='\0'; bufIdx = 0; /* Identify the field and build the TA_ReadOp. */ tempInt = 0; retCode = buildReadOp( newReadOpInfo, (const char *)&localBuf[0], &arrayReadOp[opIdx], &tempToken, &tempInt ); if( retCode != TA_SUCCESS ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( retCode ); } if( arrayReadOp[opIdx] != 0 ) { /* Set the replace zero flag as needed */ if( TA_IS_REPLACE_ZERO(readOpFlags) && TA_IS_REAL_CMD(arrayReadOp[opIdx]) ) { TA_SET_REPLACE_ZERO(arrayReadOp[opIdx]); } /* Set the skipNonDigitLine flag as needed. */ if( skipNonDigitLine == 1 ) { TA_SET_SKIP_NDL_FLAG(arrayReadOp[opIdx]); } /* Ooof... this readOp is now all build! */ opIdx++; } /* If this is a time token, make sure this * is not in contradiction with an already * specified increment. */ if( intraDayIncPeriod ) { errorOccurred = 0; switch( tempToken ) { case TA_TOK_SEC: case TA_TOK_SS: if( (intraDayIncToken == TA_TOK_MIN) || (intraDayIncToken == TA_TOK_MN) ) errorOccurred = 1; /* no break */ case TA_TOK_MIN: case TA_TOK_MN: if( (intraDayIncToken == TA_TOK_HOUR) || (intraDayIncToken == TA_TOK_HH) ) errorOccurred = 1; break; case TA_TOK_HOUR: case TA_TOK_HH: errorOccurred = 1; break; default: /* Do nothing */ break; } if( errorOccurred ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } } /* Check if a period increment is specified. */ if( (tempInt != 0) && (tempInt != 1) ) { if( intraDayIncPeriod != 0 ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } intraDayIncPeriod = tempInt; intraDayIncToken = tempToken; } break; default: if( bufIdx >= sizeof(localBuf)-1 ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } localBuf[bufIdx++] = *pos; break; } pos++; } if( opIdx != nbField ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INTERNAL_ERROR(89) ); } arrayReadOp[opIdx-1] |= TA_CMD_LAST_FLAG; /* Build the mask representing the fields provided. */ fieldProvided = 0; timeframeIdx = TA_INTEGER_ARRAY_SIZE; for( opIdx=0; opIdx < nbField; opIdx++ ) { readOp = arrayReadOp[opIdx]; TA_ASSERT( readOp != 0 ); /* Parano test */ if( !TA_IS_PERMANENT_SKIP_SET(readOp) ) { /* Make sure this field was not specified twice. */ for( i=opIdx+1; i < nbField; i++ ) { if( (TA_IS_REAL_CMD(readOp) && TA_IS_REAL_CMD(arrayReadOp[i])) || (TA_IS_INTEGER_CMD(readOp) && TA_IS_INTEGER_CMD(arrayReadOp[i])) ) { if( (TA_GET_IDX(readOp) == TA_GET_IDX(arrayReadOp[i])) && !TA_IS_PERMANENT_SKIP_SET(arrayReadOp[i]) ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_REDUNDANT_FIELD ); } } } /* Parano test: Double-check redundant field in a different way. */ fieldMask = TA_ReadOpToField( readOp ); TA_ASSERT( fieldMask != 0 ); if( !(fieldMask & TA_TIMESTAMP) && (fieldProvided & fieldMask) ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_REDUNDANT_FIELD ); } /* Set the field. */ fieldProvided |= fieldMask; /* Keep track of the smallest granularity of the timestamp. */ if( fieldMask & TA_TIMESTAMP ) { if( (timeframeIdx == TA_INTEGER_ARRAY_SIZE) || (TA_GET_IDX(readOp) < timeframeIdx) ) timeframeIdx = TA_GET_IDX(readOp); } } } /* No date/time reference provided!? This is considered an error * in the current implementation. */ if( timeframeIdx == TA_INTEGER_ARRAY_SIZE ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_MISSING_DATE_OR_TIME_FIELD ); } /* Determine at which point the timestamp is completed. */ flagSet = 0; for( opIdx=nbField; opIdx > 0; opIdx-- ) { ptrReadOp = &arrayReadOp[opIdx-1]; readOp = *ptrReadOp; if( !flagSet && TA_IS_INTEGER_CMD(readOp) && (TA_GET_IDX(readOp)<=TA_YEAR_IDX) && !TA_IS_PERMANENT_SKIP_SET(readOp) ) { TA_SET_TIMESTAMP_COMPLETE(*ptrReadOp); flagSet = 1; } else { TA_CLR_TIMESTAMP_COMPLETE(*ptrReadOp); } } /* Validate and identify the period. */ period = 0; if( intraDayIncPeriod ) { errorOccurred = 0; switch( timeframeIdx ) { case TA_YEAR_IDX: case TA_MONTH_IDX: case TA_DAY_IDX: errorOccurred = 1; break; case TA_HOUR_IDX: if( (intraDayIncPeriod < TA_1HOUR) || (intraDayIncPeriod >= TA_DAILY) ) errorOccurred = 1; break; case TA_MIN_IDX: if( (intraDayIncPeriod < TA_1MIN) || (intraDayIncPeriod >= TA_1HOUR) ) errorOccurred = 1; break; case TA_SEC_IDX: if( (intraDayIncPeriod < TA_1SEC) || (intraDayIncPeriod >= TA_1MIN) ) errorOccurred = 1; break; default: TA_ReadOpInfoFree( newReadOpInfo ); TA_FATAL( NULL, timeframeIdx, fieldProvided ); } if( errorOccurred ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } period = intraDayIncPeriod; } else { switch( timeframeIdx ) { case TA_YEAR_IDX: period = TA_YEARLY; break; case TA_MONTH_IDX: period = TA_MONTHLY; break; case TA_DAY_IDX: period = TA_DAILY; break; case TA_HOUR_IDX: period = TA_1HOUR; break; case TA_MIN_IDX: period = TA_1MIN; break; case TA_SEC_IDX: period = TA_1SEC; break; default: TA_FATAL( NULL, timeframeIdx, fieldProvided ); } } /* A last check... */ if( period == 0 ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } /* Everything is fine, let's return the information. */ newReadOpInfo->arrayReadOp = arrayReadOp; newReadOpInfo->fieldProvided = fieldProvided; newReadOpInfo->nbReadOp = nbField; newReadOpInfo->period = period; *allocatedInfo = newReadOpInfo; TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_FileIndexAddSymbolData( TA_Libc *libHandle, TA_FileIndexCategoryData *categoryData, TA_String *stringSymbol, TA_ValueTreeNode *treeNodeValue, TA_FileIndexSymbolData **added ) { TA_PROLOG; TA_RetCode retCode; TA_FileIndexSymbolData *symbolData; unsigned int tmpInt; unsigned int symbolFound; /* Boolean */ TA_StringCache *stringCache; TA_TRACE_BEGIN( libHandle, TA_FileIndexAddSymbolData ); stringCache = TA_GetGlobalStringCache( libHandle ); TA_ASSERT( libHandle, categoryData != NULL ); TA_ASSERT( libHandle, categoryData->listSymbol != NULL ); TA_ASSERT( libHandle, stringSymbol != NULL ); TA_ASSERT( libHandle, treeNodeValue != NULL ); if( added ) *added = NULL; /* Trap the case where this symbol is already there for that * category. In that case, the information is ignored. * Under the same category, for the same datasource, only one file * is supported for a category-symbol pair. */ symbolData = (TA_FileIndexSymbolData *)TA_ListAccessTail( categoryData->listSymbol ); symbolFound = 0; while( symbolData && !symbolFound ) { TA_ASSERT( libHandle, symbolData->string != NULL ); tmpInt = strcmp( TA_StringToChar( stringSymbol ), TA_StringToChar( symbolData->string ) ); if( tmpInt == 0 ) symbolFound = 1; else symbolData = (TA_FileIndexSymbolData *)TA_ListAccessPrev( categoryData->listSymbol ); } if( !symbolFound ) { /* This is a new symbol, so allocate the TA_FileIndexSymbolData */ symbolData = (TA_FileIndexSymbolData *)TA_Malloc( libHandle, sizeof(TA_FileIndexSymbolData) ); if( !symbolData ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } /* Initialize the TA_FileIndexSymbolData */ symbolData->parent = categoryData; symbolData->node = treeNodeValue; symbolData->string = TA_StringDup( stringCache, stringSymbol ); if( !symbolData->string ) { TA_Free( libHandle, symbolData ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } /* Add it to the category list. */ retCode = TA_ListAddTail( categoryData->listSymbol, symbolData ); if( retCode != TA_SUCCESS ) { TA_StringFree( stringCache, symbolData->string ); TA_Free( libHandle, symbolData ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } } /* Return the address of the object representing that symbol. */ if( added ) *added = symbolData; TA_TRACE_RETURN( TA_SUCCESS ); }
/**** Global functions definitions. ****/ TA_RetCode TA_FileIndexParsePath( TA_FileIndexPriv *fileIndexPriv, TA_String *path ) { typedef enum { INIT_PROCESSING, FIX_PROCESSING, FIELD_PROCESSING, WILD_PROCESSING, SEP_PROCESSING } State; TA_PROLOG State currentState; const char *currentTokenStart; unsigned int length; char *str; char *pos; char sepTmp[2]; TA_RetCode retCode; unsigned int tokenSize; TA_TokenId tokenId; const char *sourcePattern; TA_TRACE_BEGIN( TA_FileIndexParsePath ); TA_ASSERT( path != NULL ); sepTmp[1] = '\0'; sourcePattern = TA_StringToChar( path ); /* The following macro should help for the readability of the parsing logic. * These macro are used only inside this function. */ #define RETURN(y) {TA_Free(str); TA_TRACE_RETURN( y );} #define REJECT_STATE(x,y) { if(currentState==x)RETURN(y); } #define CHANGE_STATE(x) {currentState=x; currentTokenStart=pos+1;} #define ADD_TOKEN(id,value) \ { \ retCode = addToken(fileIndexPriv,id,value); \ if( retCode != TA_SUCCESS) RETURN(retCode); \ } #define FLUSH_FIX() \ { \ retCode = flushFixPart(fileIndexPriv,currentTokenStart,pos); \ if( retCode != TA_SUCCESS ) RETURN(retCode); \ } /* This function build a list representing the tokens * of the sourcePattern. * * Example: "C:\a\*AZD?\[S]\data.txt" becomes * * TokenId Value * TA_TOK_FIX "C:" * TA_TOK_SEP "\" * TA_TOK_FIX "a" * TA_TOK_SEP "\" * TA_TOK_WILD "*" * TA_TOK_FIX "AZD" * TA_TOK_WILD_CHAR "?" * TA_TOK_SEP "\" * TA_TOK_S "?*" * TA_TOK_SEP "\" * TA_TOK_FIX "data.txt" * TA_TOK_END (null) * * In the values, the '?' and '*' character represent MS-DOS kind * of wildcards: * '?' is any character (but only one). * '*' zero or more of any character */ if( sourcePattern == NULL ) return TA_INVALID_PATH; length = strlen( sourcePattern ) + 1; if( (length <= 1) || (length > 2048) ) return TA_INVALID_PATH; str = (char *)TA_Malloc( length ); strcpy( str, sourcePattern ); pos = str; currentState = INIT_PROCESSING; currentTokenStart = pos; while( *pos != '\0' ) { if( (*pos == '\\') || (*pos == '/') ) { /* Handle directories separator character. */ REJECT_STATE( FIELD_PROCESSING, TA_INVALID_FIELD ); REJECT_STATE( SEP_PROCESSING, TA_INVALID_PATH ); FLUSH_FIX(); #if 0 !!! Needed? /* Check that the string prior to the separator * does not terminate with a dot '.' */ if( currentState != INIT_PROCESSING ) { if( *(pos-1) == '.' ) RETURN( TA_INVALID_PATH ); } #endif /* Transform into the directory delimiter * used on the host file system. */ sepTmp[0] = (char)TA_SeparatorASCII(); ADD_TOKEN( TA_TOK_SEP, sepTmp ); CHANGE_STATE( SEP_PROCESSING ); } else switch( *pos )
static TA_RetCode buildReadOp( TA_ReadOpInfo *readOpInfo, const char *localBuf, TA_ReadOp *readOp, TA_TokenId *tokenId, unsigned int *intraDayIncrementInSeconds ) { TA_PROLOG TA_TokenId id; TA_ReadOp tmpReadOp; TA_RetCode retCode; TA_Integer optionalParam; unsigned int mult, intraDayIncrement; TA_TRACE_BEGIN( buildReadOp ); if( !readOp || !intraDayIncrementInSeconds || !tokenId ) { TA_TRACE_RETURN( TA_INTERNAL_ERROR(9) ); } *intraDayIncrementInSeconds = 0; *readOp = 0; *tokenId = 0; retCode = findTokenId( localBuf, &id, &optionalParam ); if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } TA_ASSERT( id != TA_TOK_END ); /* Trap special token not generating a TA_ReadOp. */ if( id == TA_TOK_SKIP_N_HEADER_LINE ) { if( optionalParam == 0 ) { TA_TRACE_RETURN( TA_INVALID_FIELD ); } readOpInfo->nbHeaderLineToSkip = optionalParam; TA_TRACE_RETURN( TA_SUCCESS ); } if( id == TA_TOK_SKIP_NON_DIGIT_LINE ) { if( optionalParam != 1 ) { TA_TRACE_RETURN( TA_INVALID_FIELD ); } TA_TRACE_RETURN( TA_SUCCESS ); } /* Integer or Real operation? */ switch( id ) { case TA_TOK_OPEN: case TA_TOK_HIGH: case TA_TOK_LOW: case TA_TOK_CLOSE: case TA_TOK_SKIP_N_REAL: tmpReadOp = TA_CMD_READ_REAL; break; case TA_TOK_YYYY: case TA_TOK_YY: case TA_TOK_Y: case TA_TOK_M: case TA_TOK_MM: case TA_TOK_MMM: case TA_TOK_D: case TA_TOK_DD: case TA_TOK_VOLUME: case TA_TOK_OPENINTEREST: case TA_TOK_HOUR: case TA_TOK_MIN: case TA_TOK_SEC: case TA_TOK_HH: case TA_TOK_MN: case TA_TOK_SS: case TA_TOK_SKIP_N_INTEGER: tmpReadOp = TA_CMD_READ_INTEGER; break; case TA_TOK_SKIP_N_CHAR: case TA_TOK_SKIP_NON_DIGIT_LINE: tmpReadOp = 0; break; default: TA_TRACE_RETURN( TA_INVALID_FIELD ); } /* Is this a permanent skip operation? */ switch( id ) { case TA_TOK_SKIP_N_CHAR: case TA_TOK_SKIP_N_INTEGER: case TA_TOK_SKIP_N_REAL: TA_SET_PERMANENT_SKIP_FLAG( tmpReadOp ); TA_SET_SKIP_FLAG( tmpReadOp ); break; default: TA_CLR_PERMANENT_SKIP_FLAG( tmpReadOp ); TA_CLR_SKIP_FLAG( tmpReadOp ); } /* Set the "numeric" parameter */ switch( id ) { case TA_TOK_SKIP_N_INTEGER: case TA_TOK_SKIP_N_REAL: case TA_TOK_SKIP_N_CHAR: TA_SET_NB_NUMERIC( tmpReadOp, optionalParam ); break; case TA_TOK_OPENINTEREST: readOpInfo->openInterestMult = optionalParam; TA_SET_NB_NUMERIC( tmpReadOp, 0 ); break; case TA_TOK_VOLUME: readOpInfo->volumeMult = optionalParam; TA_SET_NB_NUMERIC( tmpReadOp, 0 ); break; default: TA_SET_NB_NUMERIC( tmpReadOp, TA_TokenMaxSize(id) ); break; } /* Set the index information. */ switch( id ) { case TA_TOK_YYYY: case TA_TOK_YY: case TA_TOK_Y: TA_SET_IDX( tmpReadOp, TA_YEAR_IDX ); break; case TA_TOK_M: case TA_TOK_MM: case TA_TOK_MMM: TA_SET_IDX( tmpReadOp, TA_MONTH_IDX ); break; case TA_TOK_D: case TA_TOK_DD: TA_SET_IDX( tmpReadOp, TA_DAY_IDX ); break; case TA_TOK_OPEN: TA_SET_IDX( tmpReadOp, TA_OPEN_IDX ); break; case TA_TOK_HIGH: TA_SET_IDX( tmpReadOp, TA_HIGH_IDX ); break; case TA_TOK_LOW: TA_SET_IDX( tmpReadOp, TA_LOW_IDX ); break; case TA_TOK_CLOSE: TA_SET_IDX( tmpReadOp, TA_CLOSE_IDX ); break; case TA_TOK_VOLUME: TA_SET_IDX( tmpReadOp, TA_VOLUME_IDX ); break; case TA_TOK_OPENINTEREST: TA_SET_IDX( tmpReadOp, TA_OPENINTEREST_IDX ); break; case TA_TOK_HOUR: case TA_TOK_HH: TA_SET_IDX( tmpReadOp, TA_HOUR_IDX ); break; case TA_TOK_MIN: case TA_TOK_MN: TA_SET_IDX( tmpReadOp, TA_MIN_IDX ); break; case TA_TOK_SEC: case TA_TOK_SS: TA_SET_IDX( tmpReadOp, TA_SEC_IDX ); break; default: /* Do nothing. */ break; } /* Set a special flag for the TA_TOK_MMM because * it must do chat to integer processing. */ if( id == TA_TOK_MMM ) tmpReadOp |= TA_CMD_READ_MONTH_CHAR; /* Identify the time increments. */ mult = 1; intraDayIncrement = 0; switch( id ) { case TA_TOK_HOUR: case TA_TOK_HH: mult *= 60; case TA_TOK_MIN: case TA_TOK_MN: mult *= 60; case TA_TOK_SEC: case TA_TOK_SS: if( optionalParam < 1 ) { /* Shall be at least '1'... */ TA_TRACE_RETURN( TA_INVALID_FIELD ); } else if( optionalParam > 1 ) { /* When the default '1' is specified, do * not return the increment to the caller. */ intraDayIncrement = optionalParam * mult; } break; default: /* Do nothing */ break; } /* Everything is fine, return the info to the caller. */ *readOp = tmpReadOp; *intraDayIncrementInSeconds = intraDayIncrement; *tokenId = id; TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_ForEachFunc( TA_Libc *libHandle, TA_CallForEachFunc functionToCall, void *opaqueData ) { TA_PROLOG; TA_StringTable *tableGroup; TA_StringTable *tableFunc; const TA_FuncDef *funcDef; const TA_FuncHandle *funcHandle; TA_RetCode retCode; unsigned int i, j; const TA_FuncInfo *funcInfo; TA_TRACE_BEGIN( libHandle, TA_ForEachFunc ); if( functionToCall == NULL ) { TA_TRACE_RETURN( TA_BAD_PARAM ); } /* Get all the group to iterate. */ retCode = TA_GroupTableAlloc( libHandle, &tableGroup ); if( retCode == TA_SUCCESS ) { TA_ASSERT( libHandle, tableGroup != NULL ); for( i=0; i < tableGroup->size; i++ ) { TA_DEBUG_ASSERT( libHandle, tableGroup->string[i] != NULL ); /* Get all the symbols to iterate for this category. */ retCode = TA_FuncTableAlloc( libHandle, tableGroup->string[i], &tableFunc ); if( retCode == TA_SUCCESS ) { TA_DEBUG_ASSERT( libHandle, tableFunc != NULL ); for( j=0; j < tableFunc->size; j++ ) { TA_DEBUG_ASSERT( libHandle, tableFunc->string[j] != NULL ); /* Get the function handle, and then the TA_FuncDef, * and then the TA_FuncInfo... */ retCode = TA_GetFuncHandle( libHandle, tableFunc->string[j], &funcHandle ); if( retCode != TA_SUCCESS ) continue; TA_DEBUG_ASSERT( libHandle, funcHandle != NULL ); funcDef = (const TA_FuncDef *)funcHandle; TA_DEBUG_ASSERT( libHandle, funcDef != NULL ); funcInfo = funcDef->funcInfo; TA_DEBUG_ASSERT( libHandle, funcInfo != NULL ); /* Call user provided function. */ (*functionToCall)( libHandle, funcInfo, opaqueData ); } } TA_FuncTableFree( tableFunc ); } TA_GroupTableFree( tableGroup ); } else { TA_TRACE_RETURN( TA_INTERNAL_ERROR(2) ); } TA_TRACE_RETURN( TA_SUCCESS ); }
static TA_RetCode fetchUsingLibCurl( TA_NetworkGlobal *global, TA_WebPage *webPage ) { TA_PROLOG TA_RetCode retCode; TA_WebPageHiddenData *webPageHidden; const char *string1, *string2, *string3; unsigned int urlLength; char *urlString; CURLcode retValue; long curlInfo; TA_TRACE_BEGIN( fetchUsingLibCurl ); TA_ASSERT( webPage != NULL ); webPageHidden = (TA_WebPageHiddenData *)webPage->hiddenData; /* Open an internet session. */ /* Create the URL. */ string1 = "http://"; urlLength = strlen( string1 ) + 1; if( webPageHidden->webSiteAddr ) { string2 = webPageHidden->webSiteAddr; urlLength += strlen( string2 ); } else string2 = NULL; if( webPageHidden->webSitePage ) { string3 = webPageHidden->webSitePage; urlLength += strlen( string3 ) + 1; } else string3 = NULL; urlString = TA_Malloc( urlLength ); if( !urlString ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } sprintf( urlString, "%s%s%s%s", string1? string1:"", string2? string2:"", string3 && string3[0] != '/'? "/":"", string3? string3:"" ); /* Serialize the request until a stress testing * application proove that libcurl is multi-thread safe. */ #if !defined( TA_SINGLE_THREAD ) retCode = TA_SemaWait( &global->mutexSema ); if( retCode != TA_SUCCESS ) { TA_Free( urlString ); TA_TRACE_RETURN( retCode ); } #endif /* Specify URL to get */ curl_easy_setopt(global->curlHandle, CURLOPT_URL, urlString ); /* Send all data to the callback function */ curl_easy_setopt(global->curlHandle, CURLOPT_WRITEFUNCTION, libcurlWriteMemoryCallback); /* Specify the opaque data ptr for the callback function */ curl_easy_setopt(global->curlHandle, CURLOPT_FILE, (void *)webPage); /* Fetch it. */ retValue = curl_easy_perform(global->curlHandle); if( retValue == CURLE_OK ) retCode = TA_SUCCESS; else { retValue = curl_easy_getinfo( global->curlHandle, CURLINFO_HTTP_CODE, &curlInfo ); if( retValue == CURLE_OK ) retCode = rfc1945StatusToRetCode( curlInfo ); else retCode = TA_HTTP_SC_UNKNOWN; } #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &global->mutexSema ); #endif /* Free the url. */ TA_Free( urlString ); TA_TRACE_RETURN( retCode ); }
TA_RetCode TA_SIMULATOR_GetHistoryData( TA_DataSourceHandle *handle, TA_CategoryHandle *categoryHandle, TA_SymbolHandle *symbolHandle, TA_Period period, const TA_Timestamp *start, const TA_Timestamp *end, TA_Field fieldToAlloc, TA_ParamForAddData *paramForAddData ) { TA_PROLOG TA_PrivateHandle *privateHandle; TA_RetCode retCode; TA_Timestamp *timestamp; TA_Real *open, *high, *low, *close; TA_Integer *volume; unsigned int i; (void)fieldToAlloc; (void)end; (void)start; (void)period; TA_TRACE_BEGIN( TA_SIMULATOR_GetHistoryData ); TA_ASSERT( handle != NULL ); privateHandle = (TA_PrivateHandle *)handle->opaqueData; TA_ASSERT( privateHandle != NULL ); TA_ASSERT( paramForAddData != NULL ); TA_ASSERT( categoryHandle != NULL ); TA_ASSERT( symbolHandle != NULL ); retCode = TA_INTERNAL_ERROR(98); /* Note: start/end index are currently ignored * in this data source. */ /* Identify the category. */ switch( (unsigned int)categoryHandle->opaqueData ) { case 0: /* This is TA_SIM_REF */ switch( (unsigned int)symbolHandle->opaqueData ) { case 0: timestamp = (TA_Timestamp *)NULL; open = high = low = close = (TA_Real *)NULL; volume = (TA_Integer *)NULL; #define TA_ALLOC_COPY( varName, varType, varSize) { \ varName = TA_Malloc( sizeof( varType ) * varSize ); \ if( !varName ) \ { \ FREE_IF_NOT_NULL( open ); \ FREE_IF_NOT_NULL( high ); \ FREE_IF_NOT_NULL( low ); \ FREE_IF_NOT_NULL( close ); \ FREE_IF_NOT_NULL( volume ); \ TA_TRACE_RETURN( TA_ALLOC_ERR ); \ } \ memcpy( varName, TA_SREF_##varName##_daily_ref_0_PRIV, sizeof( varType )*varSize ); } TA_ALLOC_COPY( open, TA_Real, TA_REF_DAILY_NB_BARS ); TA_ALLOC_COPY( high, TA_Real, TA_REF_DAILY_NB_BARS ); TA_ALLOC_COPY( low, TA_Real, TA_REF_DAILY_NB_BARS ); TA_ALLOC_COPY( close, TA_Real, TA_REF_DAILY_NB_BARS ); TA_ALLOC_COPY( volume, TA_Integer, TA_REF_DAILY_NB_BARS ); #undef TA_ALLOC_COPY /* Set the timestamp. */ timestamp = TA_Malloc( sizeof( TA_Timestamp ) * TA_REF_DAILY_NB_BARS ); if( !timestamp ) { TA_Free( open ); TA_Free( high ); TA_Free( low ); TA_Free( close ); TA_Free( volume ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } for( i=0; i < TA_REF_DAILY_NB_BARS; i++ ) TA_TimestampCopy( ×tamp[i], &TA_SREF_timestamp_daily_ref_0_PRIV[i] ); retCode = TA_HistoryAddData( paramForAddData, TA_REF_DAILY_NB_BARS, TA_DAILY, timestamp, open, high, low, close, volume, NULL ); break; case 1: /* Allocate the rest. */ timestamp = (TA_Timestamp *)NULL; open = high = low = close = (TA_Real *)NULL; #define TA_ALLOC_COPY( varName, varType, varSize) { \ varName = TA_Malloc( sizeof( varType ) * varSize ); \ if( !varName ) \ { \ TA_Free( timestamp ); \ FREE_IF_NOT_NULL( open ); \ FREE_IF_NOT_NULL( high ); \ FREE_IF_NOT_NULL( low ); \ FREE_IF_NOT_NULL( close ); \ TA_TRACE_RETURN( TA_ALLOC_ERR ); \ } \ memcpy( varName, TA_SREF_##varName##_daily_ref_0_PRIV, sizeof( varType )*varSize ); } TA_ALLOC_COPY( open, TA_Real, 33 ); TA_ALLOC_COPY( high, TA_Real, 33 ); TA_ALLOC_COPY( low, TA_Real, 33 ); TA_ALLOC_COPY( close, TA_Real, 33 ); #undef TA_ALLOC_COPY /* Set the timestamp. */ timestamp = (TA_Timestamp *)TA_Malloc( sizeof( TA_Timestamp ) * 33 ); if( !timestamp ) { FREE_IF_NOT_NULL( open ); FREE_IF_NOT_NULL( high ); FREE_IF_NOT_NULL( low ); FREE_IF_NOT_NULL( close ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } for( i=0; i < TA_REF_INTRA_NB_BARS; i++ ) TA_TimestampCopy( ×tamp[i], &TA_SREF_timestamp_intra_ref_0_PRIV[i] ); retCode = TA_HistoryAddData( paramForAddData, TA_REF_INTRA_NB_BARS, TA_1MIN*10, timestamp, open, high, low, close, NULL, NULL ); break; } break; case 1: /* This is TA_SIM_MRG */ retCode = addSimMrgData( privateHandle, paramForAddData ); break; } TA_TRACE_RETURN( retCode ); }
TA_RetCode TA_WebPageAllocFromYahooName( TA_Libc *libHandle, const TA_DecodingParam *decodingParam, const char *yahooName, TA_WebPage **allocatedWebPage ) { TA_PROLOG; TA_RetCode retCode; char webSitePage[300]; unsigned int prefixLength, suffixLength, symbolLength, i; const char *webSiteAddr; const char *uirPrefix, *uirSuffix; TA_WebPage *webPage; TA_TRACE_BEGIN( libHandle, TA_WebPageAllocFromYahooName ); retCode = TA_INTERNAL_ERROR(117); if( !decodingParam || !yahooName || !allocatedWebPage ) { TA_TRACE_RETURN( TA_BAD_PARAM ); } webSiteAddr = decodingParam->webSiteServer; TA_ASSERT( libHandle, webSiteAddr != NULL ); uirPrefix = decodingParam->uirPrefix; TA_ASSERT( libHandle, uirPrefix != NULL ); prefixLength = strlen( uirPrefix ); uirSuffix = decodingParam->uirSuffix; TA_ASSERT( libHandle, uirSuffix != NULL ); suffixLength = strlen( uirSuffix ); symbolLength = strlen( yahooName ); if( (symbolLength + suffixLength + prefixLength) >= 299 ) { TA_TRACE_RETURN( TA_INVALID_SECURITY_EXCHANGE ); } sprintf( webSitePage, "%s%s%s", uirPrefix, yahooName, uirSuffix ); /* Get the Web Page */ for( i=0; i < 10; i++ ) { retCode = TA_WebPageAlloc( libHandle, webSiteAddr, webSitePage, NULL, NULL, &webPage, 10 ); if( retCode == TA_SUCCESS ) break; else { /* Yahoo! is may be slow, let's sleep 1 minute */ TA_Sleep( 60 ); } } if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } *allocatedWebPage = webPage; TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_YAHOO_OpenSource( const TA_AddDataSourceParamPriv *param, TA_DataSourceHandle **handle ) { TA_PROLOG TA_DataSourceHandle *tmpHandle; TA_PrivateYahooHandle *privData; TA_RetCode retCode; TA_StringCache *stringCache; TA_CountryId countryId; TA_CountryId countryIdTemp; TA_Timestamp now; const char *locationPtr; char locationBuffer[3]; int timeout_set; /* boolean */ int i, again; unsigned int strLength, strServerLength; const char *strTemp; *handle = NULL; TA_TRACE_BEGIN( TA_YAHOO_OpenSource ); stringCache = TA_GetGlobalStringCache(); /* Verify that the requested functionality is supported or not. */ if( param->flags & TA_REPLACE_ZERO_PRICE_BAR ) { TA_TRACE_RETURN( TA_NOT_SUPPORTED ); } /* Allocate and initialize the handle. This function will also allocate the * private handle (opaque data). */ tmpHandle = TA_YAHOO_DataSourceHandleAlloc(); if( tmpHandle == NULL ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } privData = (TA_PrivateYahooHandle *)(tmpHandle->opaqueData); /* Copy some parameters in the private handle. */ privData->param = param; /* Indentify the country and replace with the default as needed. * At the same time, identify optional "server=" modifier. */ countryId = TA_Country_ID_INVALID; if( privData->param->location ) { locationPtr = TA_StringToChar(privData->param->location); /* Split into token (seperator is ';'). Check for a 2 character country * string and the optional "server=" modifier. */ i = -1; strTemp = &locationPtr[0]; strLength = 0; strServerLength = strlen(TA_SERVER_STR); again = 1; while( (++i < 1024) && again ) { if( strLength == 0 ) strTemp = &locationPtr[i]; if( locationPtr[i] == '\0' ) again = 0; if( locationPtr[i] == ';' || !again ) { if( strLength == 2 ) { locationBuffer[0] = locationPtr[i-2]; locationBuffer[1] = locationPtr[i-1]; locationBuffer[2] = '\0'; countryIdTemp = TA_CountryAbbrevToId(locationBuffer); if( countryIdTemp == TA_Country_ID_INVALID ) TA_TRACE_RETURN( TA_UNSUPPORTED_COUNTRY ); if( countryId != TA_Country_ID_INVALID ) TA_TRACE_RETURN( TA_LIMIT_OF_ONE_COUNTRY_ID_EXCEEDED ); countryId = countryIdTemp; } else if( strLength>strServerLength && (strncmp(strTemp,TA_SERVER_STR,strServerLength)==0) ) { if( privData->userSpecifiedServer ) TA_TRACE_RETURN( TA_LIMIT_OF_ONE_SERVER_EXCEEDED ); privData->userSpecifiedServer = TA_StringAllocN( stringCache, &strTemp[strServerLength], strLength-strServerLength ); TA_ASSERT( privData->userSpecifiedServer != NULL ); } else TA_TRACE_RETURN( TA_LOCATION_PARAM_INVALID ); strLength = 0; } else strLength++; } } if( countryId == TA_Country_ID_INVALID ) { /* Default is United States. */ countryId = TA_Country_ID_US; } if( privData->param->id == TA_YAHOO_ONE_SYMBOL ) { privData->index = NULL; privData->webSiteCountry = countryId; privData->webSiteSymbol = TA_StringDup(stringCache,privData->param->info); tmpHandle->nbCategory = 1; } else { /* Build the index using .dat files */ switch( countryId ) { case TA_Country_ID_US: /* United States */ case TA_Country_ID_CA: /* Canada */ case TA_Country_ID_UK: /* United Kingdom */ case TA_Country_ID_DE: /* Germany */ case TA_Country_ID_DK: /* Denmark */ case TA_Country_ID_ES: /* Spain */ case TA_Country_ID_FR: /* France */ case TA_Country_ID_IT: /* Italy */ case TA_Country_ID_SE: /* Sweden */ case TA_Country_ID_NO: /* Norway */ /* These country are currently supported. */ break; default: TA_YAHOO_DataSourceHandleFree( tmpHandle ); TA_TRACE_RETURN( TA_UNSUPPORTED_COUNTRY ); } /* Establish the timeout for local cache of the index. * Let's make it 4 business days. */ timeout_set = 0; TA_SetDefault( &now ); retCode = TA_SetDateNow( &now ); for( i=0; (i < 4) && (retCode == TA_SUCCESS); i++ ) retCode = TA_PrevWeekday( &now ); if( (i == 4) && (retCode == TA_SUCCESS) ) timeout_set = 1; /* At this point, we got all the information we * need in the handle. * Now build the TA_YahooIdx. */ retCode = TA_YahooIdxAlloc( countryId, &privData->index, TA_USE_LOCAL_CACHE|TA_USE_REMOTE_CACHE, NULL, timeout_set?&now:NULL, NULL ); if( retCode != TA_SUCCESS ) { TA_YAHOO_DataSourceHandleFree( tmpHandle ); TA_TRACE_RETURN( retCode ); } /* Set the total number of distinct category. */ tmpHandle->nbCategory = privData->index->nbCategory; } *handle = tmpHandle; TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_YAHOO_GetHistoryData( TA_DataSourceHandle *handle, TA_CategoryHandle *categoryHandle, TA_SymbolHandle *symbolHandle, TA_Period period, const TA_Timestamp *start, const TA_Timestamp *end, TA_Field fieldToAlloc, TA_ParamForAddData *paramForAddData ) { TA_PROLOG TA_RetCode tempRetCode, retCode; TA_PrivateYahooHandle *yahooHandle; int again, j; TA_TRACE_BEGIN( TA_YAHOO_GetHistoryData ); TA_ASSERT( handle != NULL ); TA_ASSERT( paramForAddData != NULL ); TA_ASSERT( categoryHandle != NULL ); TA_ASSERT( symbolHandle != NULL ); yahooHandle = (TA_PrivateYahooHandle *)handle->opaqueData; TA_ASSERT( yahooHandle != NULL ); /* If the requested period is too precise for the * period that can be provided by this data source, * simply return without error. * Since no data has been added, the TA-LIB will ignore * this data source. */ if( period < TA_DAILY ) { TA_TRACE_RETURN( TA_SUCCESS ); } /* Get the data from the WEB. * * Yahoo! sometimes have "gaps" in its data (like one * week missing), when this is being detected, we throw * away all the data up to now and start over (up to * 5 times before giving up). */ again = 5; do { retCode = TA_GetHistoryDataFromWeb( handle, categoryHandle, symbolHandle, TA_DAILY, start, end, fieldToAlloc, paramForAddData ); if( retCode == TA_DATA_GAP ) { retCode = TA_HistoryAddDataReset( paramForAddData ); if( retCode != TA_SUCCESS ) again = 0; /* Give up */ else { --again; /* Try again */ /* Sometimes giving Yahoo! a break helps. */ tempRetCode = TA_DriverShouldContinue(paramForAddData); j = 0; while( (j++ < 5) && (tempRetCode != TA_DATA_RETREIVE_TIMEOUT) ) { TA_Sleep(1); tempRetCode = TA_DriverShouldContinue(paramForAddData); } if( tempRetCode == TA_DATA_RETREIVE_TIMEOUT ) { retCode = tempRetCode; again = 0; } } } else { again = 0; /* Exit the loop */ } } while( again > 0 ); TA_TRACE_RETURN( retCode ); }
TA_RetCode TA_FileIndexAddCategoryData( TA_FileIndexPriv *data, TA_String *stringCategory, TA_FileIndexCategoryData **added ) { TA_PROLOG; TA_RetCode retCode; TA_FileIndexCategoryData *categoryData; unsigned int tmpInt; unsigned int categoryFound; /* Boolean */ TA_Libc *libHandle; TA_StringCache *stringCache; libHandle = data->libHandle; TA_TRACE_BEGIN( libHandle, TA_FileIndexAddCategoryData ); stringCache = TA_GetGlobalStringCache( libHandle ); TA_ASSERT( libHandle, data != NULL ); TA_ASSERT( libHandle, stringCategory != NULL ); /* Trap the case where the category is already added. */ categoryData = (TA_FileIndexCategoryData *)TA_ListAccessTail( data->listCategory ); categoryFound = 0; while( categoryData && !categoryFound ) { TA_ASSERT( libHandle, categoryData->string != NULL ); tmpInt = strcmp( TA_StringToChar( stringCategory ), TA_StringToChar( categoryData->string ) ); if( tmpInt == 0 ) categoryFound = 1; else categoryData = (TA_FileIndexCategoryData *)TA_ListAccessPrev( data->listCategory ); } if( !categoryFound ) { /* This is a new category, so allocate the TA_FileIndexCategoryData */ categoryData = (TA_FileIndexCategoryData *)TA_Malloc( libHandle, sizeof(TA_FileIndexCategoryData) ); if( !categoryData ) TA_TRACE_RETURN( TA_ALLOC_ERR ); /* Initialize the TA_FileIndexCategoryData */ categoryData->parent = data; if( stringCategory ) { categoryData->string = TA_StringDup( stringCache, stringCategory); /* String for this category. Can be NULL. */ if( !categoryData->string ) { TA_Free( libHandle, categoryData ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } } else categoryData->string = NULL; categoryData->listSymbol = TA_ListAlloc( libHandle ); if( !categoryData->listSymbol ) { if( categoryData->string ) TA_StringFree( stringCache, categoryData->string ); TA_Free( libHandle, categoryData ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } /* Add it to the TA_FileIndexPriv */ retCode = TA_ListAddTail( data->listCategory, categoryData ); if( retCode != TA_SUCCESS ) { TA_ListFree( categoryData->listSymbol ); if( categoryData->string ) TA_StringFree( stringCache, categoryData->string ); TA_Free( libHandle, categoryData ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } #if 0 printf( "**ADDING CATEGORY[%s]\n", TA_StringToChar( categoryData->string ) ); #endif } /* Return the address of the object representing that category. */ if( added ) *added = categoryData; TA_TRACE_RETURN( TA_SUCCESS ); }