Пример #1
0
TA_RetCode TA_PMAlloc( const TA_Timestamp  *startDate,
                       const TA_Timestamp  *endDate,
                       TA_Real              initialCapital,
                       TA_PM              **allocatedPM )
{
    TA_PM     *pm;
    TA_PMPriv *pmPriv;
    unsigned int delta;
    TA_RetCode retCode;

    /* Check all the parameters. */
    if( !allocatedPM )
        return TA_BAD_PARAM;
    *allocatedPM = NULL;

    if( !startDate || !endDate )
        return TA_BAD_PARAM;

    if( TA_TimestampValidate( startDate ) )
        return TA_BAD_START_DATE;

    if( TA_TimestampValidate( endDate ) || TA_TimestampGreater( startDate, endDate ) )
        return TA_BAD_END_DATE;

    /* To keep things simple, it is assumed that
     * the requested date range contains at least
     * one weekday.
     */
    retCode = TA_TimestampDeltaWeekday( startDate, endDate, &delta );
    if( retCode != TA_SUCCESS )
        return retCode;
    if( delta <= 0 )
        return TA_NO_WEEKDAY_IN_DATE_RANGE;

    /* Allocate the public and private structure. */
    pm = TA_Malloc( sizeof( TA_PM ) + sizeof( TA_PMPriv ) );
    if( !pm )
        return TA_ALLOC_ERR;

    memset( pm, 0, sizeof( TA_PM ) + sizeof( TA_PMPriv ) );
    pmPriv = (TA_PMPriv *)(((char *)pm)+sizeof(TA_PM));
    pmPriv->magicNb        = TA_PMPRIV_MAGIC_NB;
    pmPriv->initialCapital = initialCapital;
    pm->hiddenData         = pmPriv;

    TA_ListInit(  &pmPriv->tradeLogList );

    /* TA_PMFree can be safely called from this point. */

    TA_TimestampCopy( &pmPriv->endDate, endDate );
    TA_TimestampCopy( &pmPriv->startDate, startDate );

    /* Success, return the allocated data to the caller. */
    *allocatedPM = pm;

    return TA_SUCCESS;
}
Пример #2
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;
}
Пример #3
0
static TA_Timestamp *allocTimestampArray( const TA_Timestamp *start,
                                          const TA_Timestamp *end,
                                          int                *nbDays )
{
   TA_RetCode    retCode;
   TA_Timestamp *array;
   int outIdx;
   TA_Timestamp curDate;
   TA_DayOfWeek dayOfTheWeek;

   TA_ASSERT_RET( TA_TimestampValidate(start) == TA_SUCCESS, (TA_Timestamp *)NULL );
   TA_ASSERT_RET( TA_TimestampValidate(end  ) == TA_SUCCESS, (TA_Timestamp *)NULL );
   TA_ASSERT_RET( nbDays != NULL, (TA_Timestamp *)NULL );

   /* Calculate the exact number of week days
    * between start and end inclusive.
    * Excluding week-ends.
    */
   retCode = TA_TimestampDeltaWeekday( start, end, (unsigned int *)nbDays );
   if( retCode != TA_SUCCESS )
      return (TA_Timestamp *)NULL;

   /* Allocate the array. Add two element just to be on the safe side. */
   array = TA_Malloc( sizeof( TA_Timestamp ) * ((*nbDays)+2) );
   if( !array )
      return (TA_Timestamp *)NULL;

   /* Fill up the array. */
   TA_TimestampCopy( &curDate, start );

   /* Write the start point, if it is a weekday. */
   outIdx = 0;
   dayOfTheWeek = TA_GetDayOfTheWeek( &curDate );
   if( (dayOfTheWeek != TA_SUNDAY) && (dayOfTheWeek != TA_SATURDAY) )
   {
      TA_TimestampCopy( &array[outIdx], &curDate );
      outIdx++;
      TA_NextWeekday( &curDate );
      TA_ASSERT_RET( TA_TimestampValidate(&curDate) == TA_SUCCESS, (TA_Timestamp *)NULL );
   }

   /* Count the number of weekday */
   while( TA_TimestampLess( &curDate, end ) )
   {
      TA_TimestampCopy( &array[outIdx], &curDate );
      outIdx++;
      TA_NextWeekday( &curDate );
      TA_ASSERT_RET( TA_TimestampValidate(&curDate) == TA_SUCCESS, (TA_Timestamp *)NULL );
   } 

   /* Check if the ending point is a weekday. */
   if( TA_TimestampEqual( &curDate, end ) )
   {
      dayOfTheWeek = TA_GetDayOfTheWeek( &curDate );
      if( (dayOfTheWeek != TA_SUNDAY) && (dayOfTheWeek != TA_SATURDAY) )
         TA_TimestampCopy( &array[outIdx++], &curDate );
   }

   TA_ASSERT_RET( outIdx == (*nbDays), (TA_Timestamp *)NULL );

   return array;
}