/* TA-LIB Copyright (c) 1999-2025, Mario Fortier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
*   notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
*   notice, this list of conditions and the following disclaimer in
*   the documentation and/or other materials provided with the
*   distribution.
*
* - Neither name of author nor the names of its contributors
*   may be used to endorse or promote products derived from this
*   software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* AUTO-GENERATED by ta_codegen — DO NOT EDIT.
* Source of truth: ta_codegen/input/<name>/  (regenerate: cd ta_codegen/generator && cargo run -- generate)
*/

#include <string.h>
#include <math.h>
#include "ta_func.h"
#include "ta_utility.h"
#include "ta_memory.h"
#include "ta_func_unguarded.h"

/* List of contributors:
 *
 *  Initial  Name/description
 *  -------------------------------------------------------------------
 *  MF       Mario Fortier
 *
 *
 * Change history:
 *
 *  MMDDYY BY   Description
 *  -------------------------------------------------------------------
 *  112400 MF   Template creation.
 *  052603 MF   Adapt code to compile with .NET Managed C++
 *  062804 MF   Resolve div by zero bug on limit case.
 */

TA_LIB_API int TA_RSI_Lookback( int optInTimePeriod )
{
   int retValue;
   if( (int)optInTimePeriod == (int)0x80000000 )
      optInTimePeriod = 14;
   else if( (int)optInTimePeriod < 2 || (int)optInTimePeriod > 100000 )
      return -1;
   retValue = optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_RSI,Rsi);
   if( TA_GLOBALS_COMPATIBILITY == ENUM_VALUE(Compatibility,TA_COMPATIBILITY_METASTOCK,Metastock) )
   {
      retValue = retValue - 1;
   }
   return retValue;
}

TA_LIB_API TA_RetCode TA_RSI( int    startIdx,
                              int    endIdx,
                              const double inReal[],
                              int optInTimePeriod,
                              int          *outBegIdx,
                              int          *outNBElement,
                              double        outReal[] )
{
   int outIdx;
   int today;
   int lookbackTotal;
   int unstablePeriod;
   int i;
   double prevGain;
   double prevLoss;
   double prevValue;
   double savePrevValue;
   double tempValue1;
   double tempValue2;

   if( startIdx < 0 )
      return TA_OUT_OF_RANGE_START_INDEX;
   if( (endIdx < 0) || (endIdx < startIdx) )
      return TA_OUT_OF_RANGE_END_INDEX;

   if( !inReal )
      return TA_BAD_PARAM;
   if( (int)optInTimePeriod == (int)0x80000000 )
      optInTimePeriod = 14;
   else if( (int)optInTimePeriod < 2 || (int)optInTimePeriod > 100000 )
      return TA_BAD_PARAM;
   if( !outReal )
      return TA_BAD_PARAM;

   /* The following algorithm is base on the original
    * work from Wilder's and shall represent the
    * original idea behind the classic RSI.
    *
    * Metastock is starting the calculation one price
    * bar earlier. To make this possible, they assume
    * that the very first bar will be identical to the
    * previous one (no gain or loss).
    */
   /* If changing this function, please check also CMO
    * which is mostly identical (just different in one step
    * of calculation).
    */
   *outBegIdx= 0;
   *outNBElement= 0;
   /* Adjust startIdx to account for the lookback period. */
   lookbackTotal = (int)TA_RSI_Lookback(optInTimePeriod);
   if( startIdx < lookbackTotal )
   {
      startIdx = lookbackTotal;
   }
   /* Make sure there is still something to evaluate. */
   if( startIdx > endIdx )
   {
      return TA_SUCCESS;
   }
   outIdx = 0;
   /* Index into the output. */
   /* Trap special case where the period is '1'.
    * In that case, just copy the input into the
    * output for the requested range (as-is !)
    */
   if( optInTimePeriod == 1 )
   {
      *outBegIdx= startIdx;
      i = (int)(endIdx - startIdx + 1);
      *outNBElement= (int)i;
      memcpy(&outReal[0],&inReal[startIdx],i * sizeof(double));
      return TA_SUCCESS;
   }
   /* Accumulate Wilder's "Average Gain" and "Average Loss"
    * among the initial period.
    */
   today = startIdx - lookbackTotal;
   prevValue = (double)inReal[today];
   unstablePeriod = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_RSI,Rsi);
   /* If there is no unstable period,
    * calculate the 'additional' initial
    * price bar who is particuliar to
    * metastock.
    * If there is an unstable period,
    * no need to calculate since this
    * first value will be surely skip.
    */
   if( unstablePeriod == 0 && TA_GLOBALS_COMPATIBILITY == ENUM_VALUE(Compatibility,TA_COMPATIBILITY_METASTOCK,Metastock) )
   {
      /* Preserve prevValue because it may get
       * overwritten by the output.
       * (because output ptr could be the same as input ptr).
       */
      savePrevValue = prevValue;
      /* No unstable period, so must calculate first output
       * particular to Metastock.
       * (Metastock re-use the first price bar, so there
       *  is no loss/gain at first. Beats me why they
       *  are doing all this).
       */
      prevGain = 0.0;
      prevLoss = 0.0;
      for( i = optInTimePeriod; i > 0; i -= 1 )
      {
         tempValue1 = (double)inReal[today];
         today = today + 1;
         tempValue2 = tempValue1 - prevValue;
         prevValue = tempValue1;
         if( tempValue2 < 0.0 )
         {
            prevLoss -= tempValue2;
         } else 
         {
            prevGain += tempValue2;
         }
      }
      tempValue1 = prevLoss / (double)optInTimePeriod;
      tempValue2 = prevGain / (double)optInTimePeriod;
      /* Write the output. */
      tempValue1 = tempValue2 + tempValue1;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (tempValue2 / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
      /* Are we done? */
      if( today > endIdx )
      {
         *outBegIdx= startIdx;
         *outNBElement= outIdx;
         return TA_SUCCESS;
      }
      /* Start over for the next price bar. */
      today = today - (int)optInTimePeriod;
      prevValue = savePrevValue;
   }
   /* Remaining of the processing is identical
    * for both Classic calculation and Metastock.
    */
   prevGain = 0.0;
   prevLoss = 0.0;
   today = today + 1;
   for( i = optInTimePeriod; i > 0; i -= 1 )
   {
      tempValue1 = (double)inReal[today];
      today = today + 1;
      tempValue2 = tempValue1 - prevValue;
      prevValue = tempValue1;
      if( tempValue2 < 0.0 )
      {
         prevLoss -= tempValue2;
      } else 
      {
         prevGain += tempValue2;
      }
   }
   /* Subsequent prevLoss and prevGain are smoothed
    * using the previous values (Wilder's approach).
    *  1) Multiply the previous by 'period-1'.
    *  2) Add today value.
    *  3) Divide by 'period'.
    */
   prevLoss /= (double)optInTimePeriod;
   prevGain /= (double)optInTimePeriod;
   /* Often documentation present the RSI calculation as follow:
    *    RSI = 100 - (100 / 1 + (prevGain/prevLoss))
    *
    * The following is equivalent:
    *    RSI = 100 * (prevGain/(prevGain+prevLoss))
    *
    * The second equation is used here for speed optimization.
    */
   if( today > startIdx )
   {
      tempValue1 = prevGain + prevLoss;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (prevGain / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
   } else 
   {
      /* Skip the unstable period. Do the processing
       * but do not write it in the output.
       */
      while( today < startIdx )
      {
         tempValue1 = (double)inReal[today];
         tempValue2 = tempValue1 - prevValue;
         prevValue = tempValue1;
         prevLoss *= (double)(optInTimePeriod - 1);
         prevGain *= (double)(optInTimePeriod - 1);
         if( tempValue2 < 0.0 )
         {
            prevLoss -= tempValue2;
         } else 
         {
            prevGain += tempValue2;
         }
         prevLoss /= (double)optInTimePeriod;
         prevGain /= (double)optInTimePeriod;
         today = today + 1;
      }
   }
   /* Unstable period skipped... now continue
    * processing if needed.
    */
   while( today <= endIdx )
   {
      tempValue1 = (double)inReal[today];
      today = today + 1;
      tempValue2 = tempValue1 - prevValue;
      prevValue = tempValue1;
      prevLoss *= (double)(optInTimePeriod - 1);
      prevGain *= (double)(optInTimePeriod - 1);
      if( tempValue2 < 0.0 )
      {
         prevLoss -= tempValue2;
      } else 
      {
         prevGain += tempValue2;
      }
      prevLoss /= (double)optInTimePeriod;
      prevGain /= (double)optInTimePeriod;
      tempValue1 = prevGain + prevLoss;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (prevGain / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
   }
   *outBegIdx= startIdx;
   *outNBElement= outIdx;
   return TA_SUCCESS;
}

TA_LIB_API TA_RetCode TA_RSI_Unguarded( int    startIdx,
                                        int    endIdx,
                                        const double inReal[],
                                        int optInTimePeriod,
                                        int          *outBegIdx,
                                        int          *outNBElement,
                                        double        outReal[] )
{
   int outIdx;
   int today;
   int lookbackTotal;
   int unstablePeriod;
   int i;
   double prevGain;
   double prevLoss;
   double prevValue;
   double savePrevValue;
   double tempValue1;
   double tempValue2;

   *outBegIdx= 0;
   *outNBElement= 0;
   lookbackTotal = (int)TA_RSI_Lookback(optInTimePeriod);
   if( startIdx < lookbackTotal )
   {
      startIdx = lookbackTotal;
   }
   if( startIdx > endIdx )
   {
      return TA_SUCCESS;
   }
   outIdx = 0;
   if( optInTimePeriod == 1 )
   {
      *outBegIdx= startIdx;
      i = (int)(endIdx - startIdx + 1);
      *outNBElement= (int)i;
      memcpy(&outReal[0],&inReal[startIdx],i * sizeof(double));
      return TA_SUCCESS;
   }
   today = startIdx - lookbackTotal;
   prevValue = (double)inReal[today];
   unstablePeriod = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_RSI,Rsi);
   if( unstablePeriod == 0 && TA_GLOBALS_COMPATIBILITY == ENUM_VALUE(Compatibility,TA_COMPATIBILITY_METASTOCK,Metastock) )
   {
      savePrevValue = prevValue;
      prevGain = 0.0;
      prevLoss = 0.0;
      for( i = optInTimePeriod; i > 0; i -= 1 )
      {
         tempValue1 = (double)inReal[today];
         today = today + 1;
         tempValue2 = tempValue1 - prevValue;
         prevValue = tempValue1;
         if( tempValue2 < 0.0 )
         {
            prevLoss -= tempValue2;
         } else 
         {
            prevGain += tempValue2;
         }
      }
      tempValue1 = prevLoss / (double)optInTimePeriod;
      tempValue2 = prevGain / (double)optInTimePeriod;
      tempValue1 = tempValue2 + tempValue1;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (tempValue2 / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
      if( today > endIdx )
      {
         *outBegIdx= startIdx;
         *outNBElement= outIdx;
         return TA_SUCCESS;
      }
      today = today - (int)optInTimePeriod;
      prevValue = savePrevValue;
   }
   prevGain = 0.0;
   prevLoss = 0.0;
   today = today + 1;
   for( i = optInTimePeriod; i > 0; i -= 1 )
   {
      tempValue1 = (double)inReal[today];
      today = today + 1;
      tempValue2 = tempValue1 - prevValue;
      prevValue = tempValue1;
      if( tempValue2 < 0.0 )
      {
         prevLoss -= tempValue2;
      } else 
      {
         prevGain += tempValue2;
      }
   }
   prevLoss /= (double)optInTimePeriod;
   prevGain /= (double)optInTimePeriod;
   if( today > startIdx )
   {
      tempValue1 = prevGain + prevLoss;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (prevGain / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
   } else 
   {
      while( today < startIdx )
      {
         tempValue1 = (double)inReal[today];
         tempValue2 = tempValue1 - prevValue;
         prevValue = tempValue1;
         prevLoss *= (double)(optInTimePeriod - 1);
         prevGain *= (double)(optInTimePeriod - 1);
         if( tempValue2 < 0.0 )
         {
            prevLoss -= tempValue2;
         } else 
         {
            prevGain += tempValue2;
         }
         prevLoss /= (double)optInTimePeriod;
         prevGain /= (double)optInTimePeriod;
         today = today + 1;
      }
   }
   while( today <= endIdx )
   {
      tempValue1 = (double)inReal[today];
      today = today + 1;
      tempValue2 = tempValue1 - prevValue;
      prevValue = tempValue1;
      prevLoss *= (double)(optInTimePeriod - 1);
      prevGain *= (double)(optInTimePeriod - 1);
      if( tempValue2 < 0.0 )
      {
         prevLoss -= tempValue2;
      } else 
      {
         prevGain += tempValue2;
      }
      prevLoss /= (double)optInTimePeriod;
      prevGain /= (double)optInTimePeriod;
      tempValue1 = prevGain + prevLoss;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (prevGain / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
   }
   *outBegIdx= startIdx;
   *outNBElement= outIdx;
   return TA_SUCCESS;
}

TA_RetCode TA_S_RSI( int    startIdx,
                     int    endIdx,
                     const float inReal[],
                     int optInTimePeriod,
                     int          *outBegIdx,
                     int          *outNBElement,
                     double        outReal[] )
{
   int outIdx;
   int today;
   int lookbackTotal;
   int unstablePeriod;
   int i;
   double prevGain;
   double prevLoss;
   double prevValue;
   double savePrevValue;
   double tempValue1;
   double tempValue2;

   if( startIdx < 0 )
      return TA_OUT_OF_RANGE_START_INDEX;
   if( (endIdx < 0) || (endIdx < startIdx) )
      return TA_OUT_OF_RANGE_END_INDEX;

   if( !inReal )
      return TA_BAD_PARAM;
   if( (int)optInTimePeriod == (int)0x80000000 )
      optInTimePeriod = 14;
   else if( (int)optInTimePeriod < 2 || (int)optInTimePeriod > 100000 )
      return TA_BAD_PARAM;
   if( !outReal )
      return TA_BAD_PARAM;

   *outBegIdx= 0;
   *outNBElement= 0;
   lookbackTotal = (int)TA_RSI_Lookback(optInTimePeriod);
   if( startIdx < lookbackTotal )
   {
      startIdx = lookbackTotal;
   }
   if( startIdx > endIdx )
   {
      return TA_SUCCESS;
   }
   outIdx = 0;
   if( optInTimePeriod == 1 )
   {
      *outBegIdx= startIdx;
      i = (int)(endIdx - startIdx + 1);
      *outNBElement= (int)i;
      memcpy(&outReal[0],&inReal[startIdx],i * sizeof(double));
      return TA_SUCCESS;
   }
   today = startIdx - lookbackTotal;
   prevValue = (double)inReal[today];
   unstablePeriod = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_RSI,Rsi);
   if( unstablePeriod == 0 && TA_GLOBALS_COMPATIBILITY == ENUM_VALUE(Compatibility,TA_COMPATIBILITY_METASTOCK,Metastock) )
   {
      savePrevValue = prevValue;
      prevGain = 0.0;
      prevLoss = 0.0;
      for( i = optInTimePeriod; i > 0; i -= 1 )
      {
         tempValue1 = (double)inReal[today];
         today = today + 1;
         tempValue2 = tempValue1 - prevValue;
         prevValue = tempValue1;
         if( tempValue2 < 0.0 )
         {
            prevLoss -= tempValue2;
         } else 
         {
            prevGain += tempValue2;
         }
      }
      tempValue1 = prevLoss / (double)optInTimePeriod;
      tempValue2 = prevGain / (double)optInTimePeriod;
      tempValue1 = tempValue2 + tempValue1;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (tempValue2 / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
      if( today > endIdx )
      {
         *outBegIdx= startIdx;
         *outNBElement= outIdx;
         return TA_SUCCESS;
      }
      today = today - (int)optInTimePeriod;
      prevValue = savePrevValue;
   }
   prevGain = 0.0;
   prevLoss = 0.0;
   today = today + 1;
   for( i = optInTimePeriod; i > 0; i -= 1 )
   {
      tempValue1 = (double)inReal[today];
      today = today + 1;
      tempValue2 = tempValue1 - prevValue;
      prevValue = tempValue1;
      if( tempValue2 < 0.0 )
      {
         prevLoss -= tempValue2;
      } else 
      {
         prevGain += tempValue2;
      }
   }
   prevLoss /= (double)optInTimePeriod;
   prevGain /= (double)optInTimePeriod;
   if( today > startIdx )
   {
      tempValue1 = prevGain + prevLoss;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (prevGain / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
   } else 
   {
      while( today < startIdx )
      {
         tempValue1 = (double)inReal[today];
         tempValue2 = tempValue1 - prevValue;
         prevValue = tempValue1;
         prevLoss *= (double)(optInTimePeriod - 1);
         prevGain *= (double)(optInTimePeriod - 1);
         if( tempValue2 < 0.0 )
         {
            prevLoss -= tempValue2;
         } else 
         {
            prevGain += tempValue2;
         }
         prevLoss /= (double)optInTimePeriod;
         prevGain /= (double)optInTimePeriod;
         today = today + 1;
      }
   }
   while( today <= endIdx )
   {
      tempValue1 = (double)inReal[today];
      today = today + 1;
      tempValue2 = tempValue1 - prevValue;
      prevValue = tempValue1;
      prevLoss *= (double)(optInTimePeriod - 1);
      prevGain *= (double)(optInTimePeriod - 1);
      if( tempValue2 < 0.0 )
      {
         prevLoss -= tempValue2;
      } else 
      {
         prevGain += tempValue2;
      }
      prevLoss /= (double)optInTimePeriod;
      prevGain /= (double)optInTimePeriod;
      tempValue1 = prevGain + prevLoss;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (prevGain / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
   }
   *outBegIdx= startIdx;
   *outNBElement= outIdx;
   return TA_SUCCESS;
}

TA_RetCode TA_S_RSI_Unguarded( int    startIdx,
                               int    endIdx,
                               const float inReal[],
                               int optInTimePeriod,
                               int          *outBegIdx,
                               int          *outNBElement,
                               double        outReal[] )
{
   int outIdx;
   int today;
   int lookbackTotal;
   int unstablePeriod;
   int i;
   double prevGain;
   double prevLoss;
   double prevValue;
   double savePrevValue;
   double tempValue1;
   double tempValue2;

   *outBegIdx= 0;
   *outNBElement= 0;
   lookbackTotal = (int)TA_RSI_Lookback(optInTimePeriod);
   if( startIdx < lookbackTotal )
   {
      startIdx = lookbackTotal;
   }
   if( startIdx > endIdx )
   {
      return TA_SUCCESS;
   }
   outIdx = 0;
   if( optInTimePeriod == 1 )
   {
      *outBegIdx= startIdx;
      i = (int)(endIdx - startIdx + 1);
      *outNBElement= (int)i;
      memcpy(&outReal[0],&inReal[startIdx],i * sizeof(double));
      return TA_SUCCESS;
   }
   today = startIdx - lookbackTotal;
   prevValue = (double)inReal[today];
   unstablePeriod = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_RSI,Rsi);
   if( unstablePeriod == 0 && TA_GLOBALS_COMPATIBILITY == ENUM_VALUE(Compatibility,TA_COMPATIBILITY_METASTOCK,Metastock) )
   {
      savePrevValue = prevValue;
      prevGain = 0.0;
      prevLoss = 0.0;
      for( i = optInTimePeriod; i > 0; i -= 1 )
      {
         tempValue1 = (double)inReal[today];
         today = today + 1;
         tempValue2 = tempValue1 - prevValue;
         prevValue = tempValue1;
         if( tempValue2 < 0.0 )
         {
            prevLoss -= tempValue2;
         } else 
         {
            prevGain += tempValue2;
         }
      }
      tempValue1 = prevLoss / (double)optInTimePeriod;
      tempValue2 = prevGain / (double)optInTimePeriod;
      tempValue1 = tempValue2 + tempValue1;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (tempValue2 / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
      if( today > endIdx )
      {
         *outBegIdx= startIdx;
         *outNBElement= outIdx;
         return TA_SUCCESS;
      }
      today = today - (int)optInTimePeriod;
      prevValue = savePrevValue;
   }
   prevGain = 0.0;
   prevLoss = 0.0;
   today = today + 1;
   for( i = optInTimePeriod; i > 0; i -= 1 )
   {
      tempValue1 = (double)inReal[today];
      today = today + 1;
      tempValue2 = tempValue1 - prevValue;
      prevValue = tempValue1;
      if( tempValue2 < 0.0 )
      {
         prevLoss -= tempValue2;
      } else 
      {
         prevGain += tempValue2;
      }
   }
   prevLoss /= (double)optInTimePeriod;
   prevGain /= (double)optInTimePeriod;
   if( today > startIdx )
   {
      tempValue1 = prevGain + prevLoss;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (prevGain / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
   } else 
   {
      while( today < startIdx )
      {
         tempValue1 = (double)inReal[today];
         tempValue2 = tempValue1 - prevValue;
         prevValue = tempValue1;
         prevLoss *= (double)(optInTimePeriod - 1);
         prevGain *= (double)(optInTimePeriod - 1);
         if( tempValue2 < 0.0 )
         {
            prevLoss -= tempValue2;
         } else 
         {
            prevGain += tempValue2;
         }
         prevLoss /= (double)optInTimePeriod;
         prevGain /= (double)optInTimePeriod;
         today = today + 1;
      }
   }
   while( today <= endIdx )
   {
      tempValue1 = (double)inReal[today];
      today = today + 1;
      tempValue2 = tempValue1 - prevValue;
      prevValue = tempValue1;
      prevLoss *= (double)(optInTimePeriod - 1);
      prevGain *= (double)(optInTimePeriod - 1);
      if( tempValue2 < 0.0 )
      {
         prevLoss -= tempValue2;
      } else 
      {
         prevGain += tempValue2;
      }
      prevLoss /= (double)optInTimePeriod;
      prevGain /= (double)optInTimePeriod;
      tempValue1 = prevGain + prevLoss;
      if( !TA_IS_ZERO(tempValue1) )
      {
         outReal[outIdx] = 100.0 * (prevGain / tempValue1);
         outIdx = outIdx + 1;
      } else 
      {
         outReal[outIdx] = 0.0;
         outIdx = outIdx + 1;
      }
   }
   *outBegIdx= startIdx;
   *outNBElement= outIdx;
   return TA_SUCCESS;
}

