<?xml version="1.0"?>
<ScriptLibrary>
  <Script>
    <Name>Swap</Name>
    <Script>
      <Code><![CDATA[
      NUMBER _AMC_NPV[SIZE(_AMC_SimDates)];
      NUMBER UnderlyingNpv[SIZE(_AMC_SimDates) + 1];
      NUMBER i, j, lastFixedLegIndex, lastFloatLegIndex;
      lastFixedLegIndex = SIZE(FixedLegSchedule);
      lastFloatLegIndex = SIZE(FloatLegSchedule);
      FOR i IN (SIZE(_AMC_SimDates), 1, -1) DO
        UnderlyingNpv[i] = UnderlyingNpv[i + 1];
        FOR j IN (lastFixedLegIndex, 2, -1) DO
          IF FixedLegSchedule[j] >= _AMC_SimDates[i] THEN
            UnderlyingNpv[i] = UnderlyingNpv[i] + PAY( Notional * FixedRate * dcf( FixedDayCounter, FixedLegSchedule[j-1], FixedLegSchedule[j] ),
                                                   FixedLegSchedule[j], FixedLegSchedule[j], PayCurrency );
            lastFixedLegIndex = j - 1;
          END;
        END;
        FOR j IN (lastFloatLegIndex, 2, -1) DO
          IF FloatLegSchedule[j] >= _AMC_SimDates[i] THEN
            UnderlyingNpv[i] = UnderlyingNpv[i] - PAY( Notional * (FloatIndex(FixingSchedule[j-1]) + FloatSpread) * dcf( FloatDayCounter, FloatLegSchedule[j-1], FloatLegSchedule[j] ),
                                                 FixingSchedule[j-1], FloatLegSchedule[j], PayCurrency );
            lastFloatLegIndex = j - 1;
          END;
        END;
      END;
      FOR i IN (1, SIZE(_AMC_SimDates), 1) DO
        _AMC_NPV[i] = UnderlyingNpv[i];
      END;
      value = UnderlyingNpv[1];
      FOR j IN (lastFixedLegIndex, 2, -1) DO
        value = value + PAY( Notional * FixedRate * dcf( FixedDayCounter, FixedLegSchedule[j-1], FixedLegSchedule[j] ),
                                                 FixedLegSchedule[j], FixedLegSchedule[j], PayCurrency );
      END;
      FOR j IN (lastFloatLegIndex, 2, -1) DO
        value = value - PAY( Notional * (FloatIndex(FixingSchedule[j-1]) + FloatSpread) * dcf( FloatDayCounter, FloatLegSchedule[j-1], FloatLegSchedule[j] ),
                                               FixingSchedule[j-1], FloatLegSchedule[j], PayCurrency );
      END;
      ]]></Code>
      <NPV>value</NPV>
    </Script>
  </Script>

  <!-- Cash settled European EQ, FX, COM Option                                               
   
       Inputs:                                                                            
       Expiry                          option expiry date                                     
       Settlement                      option payoff settlement date                          
       Strike                          option strike                                          
       PutCall                         1 for call, -1 for put                                 
       LongShort                       1 for a long, -1 for a short position                  
       Quantity                        number of option contracts                             
       Underlying                      underlying index                                       
       PayCcy                          payment currency                                       
  -->
  <Script>
    <Name>EuropeanOption</Name>
    <Script>
      <Code>
        <![CDATA[
          NUMBER Payoff, CurrentNotional;
          Payoff = PutCall * (Underlying(Expiry) - Strike);
          Option = LOGPAY( LongShort * Quantity * max( Payoff, 0 ), Expiry, Settlement, PayCcy, 1, OptionFlow);
          CurrentNotional = Strike * Quantity;
        ]]></Code>
      <NPV>Option</NPV>
      <Results>
        <Result rename="notionalCurrency">PayCcy</Result>
        <Result rename="currentNotional">CurrentNotional</Result>
      </Results>
      <CalibrationSpec>
        <Calibration>
          <Index>Underlying</Index>
          <Strikes>
            <Strike>Strike</Strike>
          </Strikes>
        </Calibration>
      </CalibrationSpec>
    </Script>
  </Script>

  <!-- Single Barrier Option

       Inputs:
       PayoffType                           0 = Vanilla max(0, S-K), 1 = Cash or Nothing
       LongShort                            long / short indicator, +1 for long, -1 for short position
       PutCall                              put / call indicator, +1 for call, -1 for put
       Quantity                             quantity for PayoffType = 0 (Vanilla)
       Strike                               the strike for PayoffType = 0 (Vanilla)
       Amount                               amount for PayoffType = 1 (Cash or Nothing)
       PayCcy                               payment currency
       Expiry                               option expiry date
       Settlement                           option settlement date
       Underlying                           the underlying index
       BarrierType                          1 = DonwIn, 2 = UpIn, 3 = DownOut, 4 = UpOut
       BarrierLevel                         barrier level
       BarrierRebate                        barrier rebate (only for out)
       BarrierRebateCurrency                barrier rebate currency
       BarrierRebatePayTime                 0 = atHit, 1 = atExpiry (only for out)
       BarrierMonitoringDates               list of barrier monitoring dates

       Results:
       Value                                NPV of the barrier option
       currentNotional                      current notional
       notionalCurrency                     current notional currency
  -->

  <Script>
    <Name>SingleBarrierOption</Name>
    <Script>
      <Code><![CDATA[
        REQUIRE PayoffType == 0 OR PayoffType == 1;
        NUMBER KnockedIn, KnockedOut, Active, Rebate;
        NUMBER U, i, d, CurrentNotional;

        FOR d IN (1, SIZE(BarrierMonitoringDates), 1) DO

          U = Underlying(BarrierMonitoringDates[d]);

          IF {BarrierType == 1 AND U <= BarrierLevel} OR
             {BarrierType == 2 AND U >= BarrierLevel} THEN
             IF KnockedOut == 0 THEN
               KnockedIn = 1;
	     END;
          END;

          IF {BarrierType == 3 AND U < BarrierLevel} OR
             {BarrierType == 4 AND U > BarrierLevel} THEN
            IF KnockedOut == 0 THEN
              IF BarrierRebatePayTime == 0 THEN
                Rebate = PAY( LongShort * BarrierRebate, BarrierMonitoringDates[d], BarrierMonitoringDates[d], BarrierRebateCurrency );
              ELSE
                Rebate = PAY( LongShort * BarrierRebate, BarrierMonitoringDates[d], Settlement, BarrierRebateCurrency );
              END;
            END;
            KnockedOut = 1;
          END;

        END;

        Active = 1;
        IF BarrierType == 1 OR BarrierType == 2 THEN
          Active = 0;
        END;
        
        Active = max(Active, KnockedIn) * (1 - KnockedOut);

	IF BarrierRebate != 0 THEN
	  Rebate = (1 - Active) * PAY( LongShort * BarrierRebate, Settlement, Settlement, BarrierRebateCurrency );
	END;

        IF PayoffType == 0 THEN
	  value = Active * PAY( LongShort * Quantity * max(0, PutCall * (Underlying(Expiry) - Strike)), Expiry, Settlement, PayCcy ) +
                  Rebate;
	ELSE
	  value = Active * PAY( LongShort * Amount, Expiry, Settlement, PayCcy ) +
                  Rebate;
	END;

        IF PayoffType == 0 THEN
          CurrentNotional = Quantity * Strike;
        ELSE
          CurrentNotional = Amount;
        END;
        ]]></Code>
      <NPV>value</NPV>
      <Results>
        <Result rename="notionalCurrency">PayCcy</Result>
        <Result rename="currentNotional">CurrentNotional</Result>
	<Result>Active</Result>
      </Results>
      <CalibrationSpec>
        <Calibration>
          <Index>Underlying</Index>
          <Strikes>
            <Strike>Strike</Strike>
            <Strike>BarrierLevel</Strike>
          </Strikes>
        </Calibration>
      </CalibrationSpec>
    </Script>
  </Script>

  <!-- Accumulator

       Inputs:
       Strike                          option strike
       FixingAmount                    unleveraged amount paid on each fixing date
       LongShort                       1 for a long, -1 for a short position
       Underlying                      underlying index
       PayCcy                          payment currency
       StartDate                       start date (only needed if AmericanKO = 1)
       FixingDates                     fixing valuation dates
       SettlementDates                 settlement dates
       RangeUpperBounds                upper bounds of fixing ranges
       RangeLowerBounds                lower bounds of fixing ranges
       RangeLeverages                  leverage amounts of fixing ranges
       KnockOutLevel                   knock out level
       KnockOutType                    barrier type 3=DownOut, 4=UpOut
       AmericanKO                      1 for American KO style, -1 for European KO style
       GuaranteedFixings               the number of fixings guaranteed regardless of knockout level

       Results:
       value                           npv of the option
       CurrentNotional                 current notional
       notionalCurrency                notional currency
  -->
  <Script>
    <Name>Accumulator</Name>
    <Script>
      <Code><![CDATA[
            REQUIRE KnockOutType == 3 OR KnockOutType == 4;
            NUMBER Payoff, fix, d, r, Alive, CurrentNotional, Factor, ThisPayout, Fixing[SIZE(FixingDates)];
            Alive = 1;
            FOR d IN (1, SIZE(FixingDates), 1) DO
                fix = Underlying(FixingDates[d]);
                Fixing[d] = fix;

                IF AmericanKO == 1 THEN
                  IF KnockOutType == 4 THEN
                    IF FixingDates[d] >= StartDate THEN
                       IF d == 1 OR FixingDates[d-1] <= StartDate THEN
                          Alive = Alive * (1 - ABOVEPROB(Underlying, StartDate, FixingDates[d], KnockOutLevel));
		       ELSE
                          Alive = Alive * (1 - ABOVEPROB(Underlying, FixingDates[d-1], FixingDates[d], KnockOutLevel));
		       END;
                    END;
                  ELSE
                    IF FixingDates[d] >= StartDate THEN
                       IF d == 1 OR FixingDates[d-1] <= StartDate THEN
                          Alive = Alive * (1 - BELOWPROB(Underlying, StartDate, FixingDates[d], KnockOutLevel));
		       ELSE
                          Alive = Alive * (1 - BELOWPROB(Underlying, FixingDates[d-1], FixingDates[d], KnockOutLevel));
		       END;
                    END;
                  END;
                ELSE
                  IF {KnockOutType == 4 AND fix >= KnockOutLevel} OR
                     {KnockOutType == 3 AND fix <= KnockOutLevel} THEN
                    Alive = 0;
                  END;
                END;

                IF d <= GuaranteedFixings THEN
                  Factor = 1;
                ELSE
                  Factor = Alive;
                END;

                FOR r IN (1, SIZE(RangeUpperBounds), 1) DO
                  IF fix > RangeLowerBounds[r] AND fix <= RangeUpperBounds[r] THEN
                    ThisPayout = RangeLeverages[r] * FixingAmount * (fix - Strike) * Factor;
                    IF d > GuaranteedFixings OR ThisPayout >= 0 THEN
                      Payoff = Payoff + LOGPAY(RangeLeverages[r] * FixingAmount * (fix - Strike) * Factor,
                                               FixingDates[d], SettlementDates[d], PayCcy);
                    END;
                  END;
                END;
            END;
            value = LongShort * Payoff;
            CurrentNotional = FixingAmount * Strike;
        ]]></Code>
      <NPV>value</NPV>
      <Results>
        <Result rename="notionalCurrency">PayCcy</Result>
        <Result rename="currentNotional">CurrentNotional</Result>
        <Result>Alive</Result>
        <Result>Fixing</Result>
      </Results>
      <CalibrationSpec>
        <Calibration>
          <Index>Underlying</Index>
          <Strikes>
            <Strike>Strike</Strike>
            <Strike>KnockOutLevel</Strike>
          </Strikes>
        </Calibration>
      </CalibrationSpec>
    </Script>
  </Script>

  <!-- Asian Basket EQ, FX, COM Option

       Inputs:
       Expiry                          option expiry date
       Settlement                      option payoff settlement date
       Strike                          option strike
       PutCall                         1 for call, -1 for put
       LongShort                       1 for a long, -1 for a short position
       Notional                        multiplier, number of option contracts, etc.
       Underlyings                     vector of underlying indices
       Weights                         vector of underlying weights
       PayCcy                          payment currency
       ObservationDates                observation dates

       Results:
       Option                          npv of the option
       ExerciseProbability             exercise probability of the option
       currentNotional                 current notional
       notionalCurrency                notional currency
  -->
  <Script>
    <Name>AsianBasketOption</Name>
    <Script>
      <Code><![CDATA[
      REQUIRE SIZE(Underlyings) == SIZE(Weights);

      NUMBER d, u, basketPrice, ExerciseProbability, Payoff;
      NUMBER currentNotional;

      FOR d IN (1, SIZE(ObservationDates), 1) DO
          FOR u IN (1, SIZE(Underlyings), 1) DO
              basketPrice = basketPrice + Underlyings[u](ObservationDates[d]) * Weights[u];
          END;
      END;

      basketPrice = basketPrice / SIZE(ObservationDates);

      Payoff = max(PutCall * (basketPrice - Strike), 0);

      Option = LongShort * Notional * PAY(Payoff, Expiry, Settlement, PayCcy);

      IF Payoff > 0 THEN
          ExerciseProbability = 1;
      END;

      currentNotional = Notional * Strike;
      ]]>
      </Code>
      <NPV>Option</NPV>
      <Results>
        <Result>ExerciseProbability</Result>
        <Result>currentNotional</Result>
        <Result rename="notionalCurrency">PayCcy</Result>
      </Results>
    </Script>
  </Script>
  
  <!-- TaRF

       Input Data:
       FixingAmount                    unleveraged amount paid on each fixing date
       LongShort                       1 for a long, -1 for a short position
       Underlying                      underlying index
       PayCcy                          payment currency
       FixingDates                     fixing valuation dates
       SettlementDates                 settlement dates
       RangeUpperBounds                upper bounds of fixing ranges
       RangeLowerBounds                lower bounds of fixing ranges
       RangeLeverages                  leverage amounts of fixing ranges
       RangeStrikes                    option strikes per range
       KnockOutProfitAmount            if > 0, trigger for accumulated profit
       KnockOutProfitEvents            if > 0, trigger for number of profit events
       TargetAmount                    target amount for TargetType = exact
       TargetType                      -1 for truncated, 0 for exact, 1 for full

       Result Data:
       value                           npv of the option
       currentNotional                 current notional
       notionalCurrency                notional currency
  -->
  <Script>
    <Name>TaRF</Name>
    <ProductTag>SingleAssetOption({AssetClass})</ProductTag>
    <Script>
      <Code><![CDATA[
            REQUIRE FixingAmount > 0;
            REQUIRE LongShort == 1 OR LongShort == -1;
            REQUIRE SIZE(RangeUpperBounds) == SIZE(RangeLowerBounds);
            REQUIRE SIZE(RangeLowerBounds) == SIZE(RangeLeverages);
            REQUIRE SIZE(RangeLowerBounds) == SIZE(RangeStrikes);
            REQUIRE TargetType == -1 OR TargetType == 0 OR TargetType == 1;
            REQUIRE SIZE(FixingDates) == SIZE(SettlementDates);

            NUMBER Payoff, d, r, PnL, wasTriggered, AccProfit, Hits, currentNotional;
            NUMBER Fixing[SIZE(FixingDates)], Triggered[SIZE(FixingDates)];

            FOR r IN (1, SIZE(RangeUpperBounds), 1) DO
              REQUIRE RangeLowerBounds[r] <= RangeUpperBounds[r];
              REQUIRE RangeStrikes[r] >= 0;
            END;
	    
            FOR d IN (1, SIZE(FixingDates), 1) DO
              Fixing[d] = Underlying(FixingDates[d]);
              IF wasTriggered != 1 THEN
                PnL = 0;
                FOR r IN (1, SIZE(RangeUpperBounds), 1) DO
                  IF Fixing[d] > RangeLowerBounds[r] AND Fixing[d] <= RangeUpperBounds[r] THEN
                    PnL = PnL + RangeLeverages[r] * FixingAmount * (Fixing[d] - RangeStrikes[r]);
                  END;
                END;

                IF PnL >= 0 THEN
                  AccProfit = AccProfit + PnL;
                  Hits = Hits + 1;
                END;

                IF {KnockOutProfitEvents > 0 AND Hits >= KnockOutProfitEvents} OR
                   {KnockOutProfitAmount > 0 AND AccProfit >= KnockOutProfitAmount} THEN
                  wasTriggered = 1;
                  Triggered[d] = 1;
                  IF TargetType == 0 THEN
                    Payoff = Payoff + LOGPAY(TargetAmount - (AccProfit - PnL), FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);
                  END;
                  IF TargetType == 1 THEN
                    Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);
                  END;
                ELSE
                    Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);
                END;
              END;
            END;
            value = LongShort * Payoff;
            currentNotional = FixingAmount * RangeStrikes[1];
        ]]></Code>
      <NPV>value</NPV>
      <Results>
        <Result>currentNotional</Result>
        <Result rename="notionalCurrency">PayCcy</Result>
        <Result>Fixing</Result>
        <Result>Triggered</Result>
      </Results>
    </Script>
  </Script>

</ScriptLibrary>
