コード例 #1
0
/* 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 );
}
コード例 #2
0
ファイル: ta_dict.c プロジェクト: royratcliffe/ta-lib
TA_RetCode TA_DictAddPair_S2( TA_Dict *dict,
                              TA_String *key1,
                              TA_String *key2,
                              void *value )
{
   TA_PrivDictInfo *theDict;
   dnode_t *node;
   TA_String *dupKey;
   TA_Dict *subDict;
   TA_Libc *libHandle;
   dict_t  *kazlibDict;

   theDict = (TA_PrivDictInfo *)dict;

   if( (theDict == NULL) ||
       (key1 == NULL) || (key2 == NULL) || (value == NULL) )
      return TA_BAD_PARAM;
   kazlibDict = &theDict->d;
   libHandle  = theDict->libHandle;

   /* Verify if a a dictionary already exist for key1. */
   node = dict_lookup( libHandle, kazlibDict, TA_StringToChar(key1) );

   if( node )
   {
      /* A dictionary already exist with the same key1... re-use it. */
      subDict = (TA_Dict *)dnode_get( node );
   }
   else
   {
      /* Alloc a new directory corresponding to key1. */
      subDict = TA_DictAlloc( libHandle, TA_DICT_KEY_ONE_STRING, theDict->freeValueFunc );

      if( !subDict )
         return TA_ALLOC_ERR;

      dupKey = TA_StringDup( TA_GetGlobalStringCache( libHandle ), key1 );

      if( !dupKey )
      {
         TA_DictFree( subDict );
         return TA_ALLOC_ERR;
      }

      if( !dict_alloc_insert( libHandle, kazlibDict, TA_StringToChar(dupKey), subDict ) )
      {
         TA_DictFree( subDict );
         TA_StringFree( TA_GetGlobalStringCache( libHandle ), dupKey );
         return TA_ALLOC_ERR;
      }
   }

   /* Insert the string in the subDict using key2 */
   return TA_DictAddPair_S( subDict, key2, value );
}
コード例 #3
0
static void internalCheckpoint( TA_TraceGlobal *global,
                                TA_String  *key,
                                const char *funcname,
                                const char *filename,
                                unsigned int lineNb )
{
   #if !defined( TA_SINGLE_THREAD )      
   TA_RetCode retCode;
   #endif

   #ifdef TA_DEBUG
   TA_TracePosition *tracePosition;
   #endif

   /* Make sure there is no tracing while tracing!
    * In rare occasion, this may prevent to record
    * some tracing in a multithread environment.
    * We can live with that compromise.
    */   
   if( !TA_IsTraceEnabled() )
      return;

   #if !defined( TA_SINGLE_THREAD )                   
      retCode = TA_SemaWait( &global->callSema );
      if( retCode != TA_SUCCESS )
         return;   
   #endif

   #ifdef TA_DEBUG
   /* If this position is already in the dictionary, just
    * increment the 'repetition' counter, else create
    * a new entry in the dictionary.
    */
   TA_TraceDisable();
   tracePosition = TA_DictGetValue_S( global->functionCalled, TA_StringToChar(key) );
   TA_TraceEnable();

   if( tracePosition )
      tracePosition->repetition++;
   else
   {
      tracePosition = newTracePosition( funcname, filename, lineNb );

      if( !tracePosition )
      {
         #if !defined( TA_SINGLE_THREAD )
            TA_SemaPost( &global->callSema );
         #endif
         return;
      }
      TA_TraceDisable();
      TA_DictAddPair_S( global->functionCalled, key, (void *)tracePosition );
      TA_TraceEnable();
   }
   /* Trace position are never deleted, until the library is shutdown.
    * Make a copy of it in the circular buffer.
    */
   global->codeTrace[global->posForNextTrace] = *tracePosition;
   #else
      (void)key; /* Used only when doing debug. */
      global->codeTrace[global->posForNextTrace].filename   = filename;
      global->codeTrace[global->posForNextTrace].funcname   = funcname;
      global->codeTrace[global->posForNextTrace].lineNb     = lineNb;
      global->codeTrace[global->posForNextTrace].repetition = 1;
   #endif

   /* Move to the next entry in the circular buffer. */
   global->posForNextTrace++;
   if( global->posForNextTrace >= TA_CODE_TRACE_SIZE )
      global->posForNextTrace = 0;

   #if !defined( TA_SINGLE_THREAD )
   TA_SemaPost( &global->callSema );
   #endif
}
コード例 #4
0
TA_RetCode TA_TradeLogAdd( TA_TradeLog    *tradeLog,
                           const TA_Transaction *newTransaction )
{
    TA_TradeLogPriv *tradeLogPriv;
    TA_Instrument *id;
    TA_Dict *theDict;
    TA_DataLog *dataLog;
    TA_TradeDictEntry *dictEntry;
    TA_StringCache *stringCache;
    TA_String *catString;
    TA_String *symString;
    const char *catCharPtr;
    const char *symCharPtr;
    TA_RetCode retCode;
    int quantity, entryTradeQuantity;
    TA_List *entryListToUse;
    TA_DataLog *entryTradeLog;

    TA_Real highestLow, highestHigh, lowestLow, lowestHigh;
    TA_Real entryPrice, tempReal;
    int i;

    retCode = TA_INTERNAL_ERROR(120);

    /* This function will transform the TA_Transaction into
     * an "entry" or multiple "trades" (because an exit can
     * be translated into multiple trade if there was multiple
     * entry point).
     */
    if( !tradeLog || !newTransaction )
        return TA_BAD_PARAM;

    /* Check that the TA_Transaction makes sense. */
    if( (newTransaction->price <= 0.0)  ||
            (newTransaction->quantity <= 0) ||
            (TA_TimestampValidate(&newTransaction->timestamp) != TA_SUCCESS) ||
            (newTransaction->type >= TA_NB_TRADE_TYPE))
        return TA_BAD_PARAM;

    /* Get access to the hidden data of the TA_TradeLog. */
    tradeLogPriv = (TA_TradeLogPriv *)tradeLog->hiddenData;

    /* Make sure this is a valid object. */
    if( !tradeLogPriv || (tradeLogPriv->magicNb != TA_TRADELOGPRIV_MAGIC_NB) )
        return TA_BAD_OBJECT;

    /* Find the TA_TradeDictEntry corresponding to
     * the TA_Instrument.
     *
     * Use the dictionary corresponding to the type of
     * key of the TA_Instrument.
     *
     * If TA_Instrument is NULL, use the pre-allocated
     * default TA_TradeDictEntry.
     */
    id = newTransaction->id;
    if( !id )
    {
        dictEntry = &tradeLogPriv->defaultDictEntry;
        catCharPtr = NULL;
        symCharPtr = NULL;
        theDict    = NULL;
    }
    else
    {
        catCharPtr = id->catString;
        symCharPtr = id->symString;
        if( catCharPtr )
        {
            if( symCharPtr )
            {
                theDict = tradeLogPriv->tradeDictCATSYM;
                dictEntry = TA_DictGetValue_S2( theDict, catCharPtr, symCharPtr );
            }
            else
            {
                theDict = tradeLogPriv->tradeDictCAT;
                dictEntry = TA_DictGetValue_S( theDict, catCharPtr );
            }
        }
        else if( symCharPtr )
        {
            theDict = tradeLogPriv->tradeDictCAT;
            dictEntry = TA_DictGetValue_S( theDict, symCharPtr );
        }
        else
        {
            theDict = tradeLogPriv->tradeDictUserKey;
            dictEntry = TA_DictGetValue_I( theDict, id->userKey );
        }
    }

    if( !dictEntry )
    {
        if( !theDict )
            return TA_INTERNAL_ERROR(146);

        /* The TA_TradeDictEntry was not found, create it! */
        dictEntry = TA_Malloc( sizeof( TA_TradeDictEntry ) );
        if( !dictEntry )
            return TA_ALLOC_ERR;

        memset( &dictEntry->id, 0, sizeof(TA_Instrument) );
        TA_ListInit( &dictEntry->shortEntryPrivList );
        TA_ListInit( &dictEntry->longEntryPrivList );

        /* Add the dictEntry to the corresponding dictionary. */
        stringCache = TA_GetGlobalStringCache();

        if( catCharPtr )
        {
            catString = TA_StringAlloc( stringCache, catCharPtr );
            if( !catString )
            {
                TA_Free( dictEntry );
                return TA_ALLOC_ERR;
            }

            if( symCharPtr )
            {
                symString = TA_StringAlloc( stringCache, symCharPtr );
                if( !symString )
                {
                    TA_Free( dictEntry );
                    TA_StringFree( stringCache, catString );
                    return TA_ALLOC_ERR;
                }
                retCode = TA_DictAddPair_S2( theDict, catString, symString, dictEntry );
                dictEntry->id.symString = TA_StringToChar(symString);
            }
            else
                retCode = TA_DictAddPair_S( theDict, catString, dictEntry );

            dictEntry->id.catString = TA_StringToChar(catString);
        }
        else if( symCharPtr )
        {
            symString = TA_StringAlloc( stringCache, symCharPtr );
            if( !symString )
            {
                TA_Free( dictEntry );
                return TA_ALLOC_ERR;
            }

            retCode = TA_DictAddPair_S( theDict, symString, dictEntry );
            dictEntry->id.symString = TA_StringToChar(symString);
        }
        else
        {
            retCode = TA_DictAddPair_I( theDict, id->userKey, dictEntry );
            dictEntry->id.userKey = id->userKey;
        }

        /* Check the retCode of the TA_DictAddXXXXX function. */
        if( retCode != TA_SUCCESS )
        {
            TA_Free( dictEntry );
            return TA_ALLOC_ERR;
        }
    }

    /* Identify the approriate list of entry. */
    switch( newTransaction->type )
    {
    case TA_LONG_ENTRY:
    case TA_LONG_EXIT:
        entryListToUse = &dictEntry->longEntryPrivList;
        break;
    case TA_SHORT_ENTRY:
    case TA_SHORT_EXIT:
        entryListToUse = &dictEntry->shortEntryPrivList;
        break;
    default:
        return TA_BAD_PARAM;
    }

    /* The sign of the quantity indicates if the
     * data log is a completed trade (+) or an
     * entry (-).
     */
    switch( newTransaction->type )
    {
    case TA_LONG_ENTRY:
    case TA_SHORT_ENTRY:
        /* Allocate a data log and add it to the list. */
        dataLog = TA_AllocatorForDataLog_Alloc( &tradeLogPriv->allocator );
        if( !dataLog )
            return TA_ALLOC_ERR;
        dataLog->u.entry.quantity  = -(newTransaction->quantity);
        dataLog->u.entry.entryPrice = newTransaction->price;
        TA_TimestampCopy( &dataLog->u.entry.entryTimestamp,
                          &newTransaction->timestamp );
        TA_ListNodeAddTail( entryListToUse, &dataLog->u.entry.node, dataLog );
        break;

    case TA_LONG_EXIT:
    case TA_SHORT_EXIT:
        /* Invalidate cached calculation of this trade log. */
        tradeLogPriv->flags &= ~TA_PMVALUECACHE_CALCULATED;

        /* Transform this transaction into one or
         * multiple trade(s).
         */
        entryTradeLog = TA_ListRemoveHead( entryListToUse );
        if( !entryTradeLog )
            return TA_ENTRY_TRANSACTION_MISSING;

        quantity = newTransaction->quantity;
        while( quantity )
        {
            entryTradeQuantity = -entryTradeLog->u.trade.quantity;
            if( entryTradeQuantity == quantity )
            {
                /* This entry have exactly the right amount of
                 * position for what needs to be closed.
                 * Just transform the entry into a trade.
                 */
                entryTradeLog->u.trade.quantity = quantity;
                entryTradeLog->u.trade.id = id;
                TA_TimestampCopy( &entryTradeLog->u.trade.exitTimestamp,
                                  &newTransaction->timestamp );
                /* Calculate the profit and make the entryPrice
                 * negative if this is a short trade.
                 * Both are multiplied by the quantity being
                 * traded.
                 */
                entryPrice = entryTradeLog->u.entry.entryPrice;
                if( newTransaction->type == TA_LONG_EXIT )
                {
                    entryTradeLog->u.trade.profit = (newTransaction->price-entryPrice)*quantity;
                    CALC_EXCURSION_LONG;
                }
                else
                {
                    entryTradeLog->u.trade.profit = (entryPrice-newTransaction->price)*quantity;
                    entryPrice = -entryPrice;
                    CALC_EXCURSION_SHORT;
                }
                entryTradeLog->u.entry.entryPrice = entryPrice * quantity;

                return TA_SUCCESS; /* Done! */
            }
            else if( entryTradeQuantity < quantity )
            {
                /* This entry have less than the amount of
                 * position that needs to be closed.
                 * Just transform the entry into a trade
                 * and move to the next entry.
                 */
                entryTradeLog->u.trade.quantity = entryTradeQuantity;
                quantity -= entryTradeQuantity;
                entryTradeLog->u.trade.id = id;
                TA_TimestampCopy( &entryTradeLog->u.trade.exitTimestamp,
                                  &newTransaction->timestamp );
                /* Calculate the profit and make the entryPrice
                 * negative if this is a short trade.
                 * Both are multiplied by the quantity being
                 * traded.
                 */
                entryPrice = entryTradeLog->u.trade.entryPrice;
                if( newTransaction->type == TA_LONG_EXIT )
                {
                    entryTradeLog->u.trade.profit = (newTransaction->price-entryPrice)*entryTradeQuantity;
                    CALC_EXCURSION_LONG;
                }
                else
                {
                    entryTradeLog->u.trade.profit = (entryPrice-newTransaction->price)*entryTradeQuantity;
                    entryPrice = -entryPrice;
                    CALC_EXCURSION_SHORT;
                }
                entryTradeLog->u.trade.entryPrice = entryPrice * entryTradeQuantity;

                /* Move to the next entry. If none available, that means there
                 * was more "exit" than "entry" and this is considered an
                 * error.
                 */
                entryTradeLog = TA_ListRemoveHead( entryListToUse );
                if( !entryTradeLog )
                    return TA_ENTRY_TRANSACTION_MISSING;
            }
            else
            {
                /* This entry have more position than what the
                 * exit requires, so the entry must be preserved.
                 * Consequently, a new tradeLog must be allocated.
                 */
                dataLog = TA_AllocatorForDataLog_Alloc( &tradeLogPriv->allocator );
                if( !dataLog )
                    return TA_ALLOC_ERR;

                TA_TimestampCopy( &dataLog->u.trade.entryTimestamp,
                                  &entryTradeLog->u.trade.entryTimestamp );
                TA_TimestampCopy( &dataLog->u.trade.exitTimestamp,
                                  &newTransaction->timestamp );
                dataLog->u.trade.quantity = quantity;
                entryPrice = entryTradeLog->u.trade.entryPrice;
                if( newTransaction->type == TA_LONG_EXIT )
                {
                    dataLog->u.trade.profit = (newTransaction->price-entryPrice)*quantity;
                    CALC_EXCURSION_LONG;
                }
                else
                {
                    dataLog->u.trade.profit = (entryPrice-newTransaction->price)*quantity;
                    entryPrice = -entryPrice;
                    CALC_EXCURSION_SHORT;
                }
                dataLog->u.trade.entryPrice = entryPrice*quantity;
                dataLog->u.trade.id = id;

                /* Adjust the entry and put it back for being process
                 * again later.
                 */
                entryTradeLog->u.trade.quantity += quantity;
                TA_ListNodeAddHead( entryListToUse, &entryTradeLog->u.entry.node, entryTradeLog );
                return TA_SUCCESS; /* Done! */
            }
        }
        break;
    default:
        return TA_INTERNAL_ERROR(121);
    }

    return TA_SUCCESS;
}