# FpML 5.3 Validation Rules - Rules for FX Derivatives

This is the FX part of the validation rule set accompanying the FpML 5.3 Working Draft #2. The introductory section in the validation section of the specifications contains background information and documentation for this page.

The rules contained on this page contain links to cut down versions of valid and invalid test cases. The cut down test cases are non-normative and are provided for the purpose of documentation only.

As part of the redesign of the existing FX product model, FX business validation rules were simplified (some of the existing rules were removed and a couple of new rules were added). Note: a few of the FX business validation rules are still under review and will be added with the next release.

## Content

- Definitions
  - calculated schedule dates
- Namespace
- Functions
- Rules
- Rules with comments
  - fx-10
  - fx-12
  - fx-20
  - fx-50

## Namespace

default element namespace = http://www.fpml.org/spec/fpml-5-3-2-wd-2

namespace xs = http://www.w3.org/2001/XMLSchema

## Definitions

Term: calculated schedule dates
Correctly evaluating rule fx-12 requires generation of a schedule of observation dates based on the observation start date, the observation end date, a calculation period frequency, a date roll convention, and a business day calendar for business calendar location where fixing occurs. The calculation should proceed as follows:

- generatedDates := [null];
- unadjustedDate := observationStartDate;
- while unadjustedDate le observationEndDate do
  - begin
    - adjustedDate := dateRoll (unadjustedDate,dateRollConvention,businessDayCalendar);
    - if adjustedDate [doesn't belong at] generatedDates then
      - generatedDates := generatedDate [union] adjustedDate;
    - unadjustedDate := unadjustedDate + calculationPeriodFrequency;
  - end;
- return (generatedDates);

The algorithm assumes that implementations can add a time period (e.g. 1D, 1W, 2M, 6M, 1Y, etc.) to dates and understands how perform standard financial date rolls (e.g. following, modified preceding, etc.) against a business day calendar. Implementations must be capable of working with dates that MAY contain time zone offset information.

## Functions

The following shared functions are used in the rules.

- same-currency-scheme

## Rules

#### Unique contexts:

- ExchangeRate (complex type): fx-3
- FxTouch (complex type): fx-8
- FxAverageRateObservationSchedule (complex type): fx-9 fx-10
- FxAsianFeature (complex type): fx-11 fx-12 fx-48
- FxBarrierFeature (complex type): fx-14
- FxSingleLeg (complex type): fx-18 fx-19
- FxSingleLeg (complex type): fx-20 fx-21
- FxOption (complex type): fx-22 fx-23
- FxSwap (complex type): fx-26
- QuotedCurrencyPair (complex type): fx-27
- CrossRate (complex type): fx-30
- TermDeposit (complex type): fx-32 fx-33
- Trade (complex type): fx-36 fx-38 fx-39 fx-40 fx-52 fx-53
- FxDigitalOption (complex type): fx-45
- FxSwapLeg (complex type): fx-49 fx-50 fx-51
- Deprecated rules
- Removed rules

fx-3 (Mandatory)
English Description:
Context: ExchangeRate (complex type)
If spotRate exists, and if forwardPoints exists, then rate is equal to the sum of spotRate and forwardPoints
XPath Description:
Context: ExchangeRate
[exists(spotRate)] [exists(forwardPoints)]
rate eq spotRate + forwardPoints
Test cases: [Invalid]
fx-8 (Mandatory)
English Description:
Context: FxTouch (complex type)
If observationStartDate exists, then observationStartDate must be before observationEndDate.
XPath Description:
Context: FxTouch
[exists(observationStartDate)]
observationStartDate le observationEndDate
Test cases: [Invalid] [Invalid] [Invalid] [Invalid]
fx-9 (Mandatory)
English Description:
Context: FxAverageRateObservationSchedule (complex type)
startDate must be before endDate
XPath Description:
Context: FxAverageRateObservationSchedule
startDate le endDate
Test cases: [Invalid]
fx-10 (Mandatory)
English Description:
Context: FxAverageRateObservationSchedule (complex type)
The observation period defined by startDate and endDate should be an integer multiple of the calculationPeriodFrequency.
Comment: See "Calculating Unadjusted Schedule Dates" section (p.10) of the "Financial Date Calculation Paper" available at: http://www.fpml.org/documents/technical.html
Test cases: [Invalid] [Invalid]
fx-11 (Mandatory)
English Description:
Context: FxAsianFeature (complex type)
The value of each rateObservation/date must be unique
XPath Description:
Context: FxAsianFeature
count(distinct-values(rateObservation/date)) eq count(rateObservation/date)
Test cases: [Invalid]
fx-12 (Implementation-specific)
English Description:
Context: FxAsianFeature (complex type)
If observationSchedule exists and If rateObservation exists, then the values of observedRates/date must be equal to a date in the calculated schedule dates derived from parameters defined within the observationSchedule element and the business day calendar implied by fixingTime/businessCenter
Comment: See "Calculating Unadjusted Schedule Dates" section (p.10) of the "Financial Date Calculation Paper" available at: http://www.fpml.org/documents/technical.html
Test cases: [Invalid]
fx-14 (Mandatory)
English Description:
Context: FxBarrierFeature (complex type)
If observationEndDate exists, then observationStartDate must be before observationEndDate
XPath Description:
Context: FxBarrierFeature
[exists(observationEndDate)]
observationStartDate le observationEndDate
Test cases: [Invalid] [Invalid]
fx-18 (Mandatory)
English Description:
Context: FxSingleLeg (complex type)
The payer and receiver of exchangedCurrency1 must have the reverse role in exchangedCurrency2.
XPath Description:
Context: FxSingleLeg
[same-currency-scheme((exchangedCurrency1/paymentAmount/currency,exchangedCurrency2/paymentAmount/currency))]
exchangedCurrency1/payerPartyReference/@href eq exchangedCurrency2/receiverPartyReference/@href and exchangedCurrency2/payerPartyReference/@href eq exchangedCurrency1/receiverPartyReference/@href and ((empty(exchangedCurrency1/payerAccountReference/@href) and empty (exchangedCurrency2/receiverAccountReference/@href)) or (exchangedCurrency1/payerAccountReference/@href eq exchangedCurrency2/receiverAccountReference/@href)) and ((empty(exchangedCurrency2/payerAccountReference/@href) and empty(exchangedCurrency1/receiverAccountReference/@href)) or (exchangedCurrency2/payerAccountReference/@href eq exchangedCurrency1/receiverAccountReference/@href))
Test cases: [Invalid]
fx-19 (Mandatory)
English Description:
Context: FxSingleLeg (complex type)
If exchangedCurrency1/paymentAmount/currency and exchangedCurrency2/paymentAmount/currency have the same-currency-scheme, then exchangedCurrency1/paymentAmount/currency must not be equal to exchangedCurrency2/paymentAmount/currency
XPath Description:
Context: FxSingleLeg
[same-currency-scheme((exchangedCurrency1/paymentAmount/currency,exchangedCurrency2/paymentAmount/currency))]
exchangedCurrency1/paymentAmount/currency ne exchangedCurrency2/paymentAmount/currency
Test cases: [Invalid]
fx-20 (Mandatory)
English Description:
Context: FxSingleLeg (complex type)
If currency1ValueDate exists, then currency1ValueDate must not be equal to currency2ValueDate.
XPath Description:
Context: FxSingleLeg
[exists(currency1ValueDate)]
currency1ValueDate ne currency2ValueDate
Comment: This rule is similar in its implementation to the rule fx-50, but used for a different type of FX product.
Test cases: [Invalid]
fx-21 (Mandatory)
English Description:
Context: FxSingleLeg (complex type)
If cashSettlement exists, then exchangeRate/forwardPoints must exist
XPath Description:
Context: FxSingleLeg
[exists(cashSettlement)]
exists(exchangeRate/forwardPoints)
Test cases: [Invalid]
fx-22 (Mandatory)
English Description:
Context: FxOption (complex type)
If premium exists, then If buyerPartyReference/@href equal to sellerPartyReference/@href, then buyerAccountReference/@href and sellerAccountReference/@href must exist and buyerAccountReference/@href must be equal to premium/payerPartyReference/@href and sellerAccountReference/@href must be equal to premium/receiverPartyReference/@href otherwise, buyerPartyReference/@href must be equal to premium/payerPartyReference/@href and sellerPartyReference/@href must be equal to premium/receiverPartyReference/@href
Test cases: [Invalid] [Invalid] [Invalid]
fx-23 (Mandatory)
English Description:
Context: FxOption (complex type)
If putCurrencyAmount/currency and callCurrencyAmount/currency have the same-currency-scheme, then putCurrencyAmount/currency must not be equal to callCurrencyAmount/currency
XPath Description:
Context: FxOption
[same-currency-scheme((putCurrencyAmount/currency,callCurrencyAmount/currency))]
putCurrencyAmount/currency ne callCurrencyAmount/currency
Test cases: [Invalid] [Invalid]
fx-26 (Mandatory)
English Description:
Context: FxSwap (complex type)
The value of nearLeg\valueDate must be before farLeg\valueDate.
XPath Description:
Context: FxSwap
nearLeg\valueDate le farLeg\valueDate
Test cases: [Invalid]
fx-27 (Mandatory)
English Description:
Context: QuotedCurrencyPair (complex type)
If currency1 and currency2 have the same-currency-scheme, then currency1 must not be equal to currency2.
XPath Description:
Context: QuotedCurrencyPair
[same-currency-scheme((currency1,currency2))]
currency1 ne currency2
Test cases: [Invalid] [Invalid]
fx-30 (Mandatory)
English Description:
Context: CrossRate (complex type)
If forwardPoints exists, then rate must be equal to the sum of spotRate and forwardPoints.
XPath Description:
Context: CrossRate
[exists(forwardPoints)]
rate eq spotRate + forwardPoints
Test cases: [Invalid]
fx-32 (Mandatory)
English Description:
Context: TermDeposit (complex type)
If payerPartyReference/@href equal to receiverPartyReference/@href, then payerAccountReference/@href and receiverAccountReference/@href must exist and the @href attribute of payerAccountReference must not be equal to the @href attribute of receiverAccountReference otherwise, the @href attribute of payerPartyReference must not be equal to the @href attribute of receiverPartyReference
Test cases: [Invalid]
fx-33 (Mandatory)
English Description:
Context: TermDeposit (complex type)
maturityDate must be after startDate
XPath Description:
Context: TermDeposit
maturityDate gt startDate
Test cases: [Invalid] [Invalid]
fx-36 (Mandatory)
English Description:
Context: Trade (complex type)
If fxOption/europeanExercise exists, then fxOption/europeanExercise/expiryDate must be after tradeHeader/tradeDate
XPath Description:
Context: Trade
[exists(fxOption/europeanExercise)]
fxOption/europeanExercise/expiryDate gt tradeHeader/tradeDate
Test cases: [Invalid] [Invalid]
fx-38 (Mandatory)
English Description:
Context: Trade (complex type)
If fxDigitalOption/europeanExercise exists, then fxDigitalOption/europeanExercise/expiryDate must be after tradeHeader/tradeDate
XPath Description:
Context: Trade
[exists(fxDigitalOption/europeanExercise)]
fxDigitalOption/europeanExercise/expiryDate gt tradeHeader/tradeDate
Test cases: [Invalid] [Invalid]
fx-39 (Mandatory)
English Description:
Context: Trade (complex type)
If fxSingleLeg exists, then the value of fxSingleLeg/valueDate or the value of both fxSingleLeg/currency1ValueDate and fxSingleLeg/currency2ValueDate must be equal to or after tradeHeader/tradeDate
XPath Description:
Context: Trade
[exists(fxSingleLeg)]
(fxSingleLeg/valueDate gte tradeHeader/tradeDate) or ((fxSingleLeg/currency1ValueDate, fxSingleLeg/currency2ValueDate) gte tradeHeader/tradeDate)
Test cases: [Invalid] [Invalid]
fx-40 (Mandatory)
English Description:
Context: Trade (complex type)
If fxSwap exists, then the value of all fxSwap/nearLeg/valueDate, or the value of both fxSwap/ nearLeg/currency1ValueDate and fxSwap/ nearLeg/currency2ValueDate must be after tradeHeader/tradeDate.
XPath Description:
Context: Trade
[exists(fxSwap)]
(fxSwap/nearLeg/valueDate gt tradeHeader/tradeDate) or ((fxSwap/nearLeg/currency1ValueDate, fxSwap/nearLeg/currency2ValueDate) gt tradeHeader/tradeDate)
Test cases: [Invalid] [Invalid]
fx-45 (Mandatory)
English Description:
Context: FxDigitalOption (complex type)
If premium exists, then if buyerPartyReference/@href equal to sellerPartyReference/@href, then buyerAccountReference/@href and sellerAccountReference/@href must exist and buyerAccountReference/@href must be equal to premium/payerAccountReference/@href and sellerAccountReference/@href must be equal to premium/receiverAccountReference/@href otherwise, buyerPartyReference/@href must be equal to premium/payerPartyReference/@href, and sellerPartyReference/@href must be equal to premium/receiverPartyReference/@href
Test cases: [Invalid]
fx-48 (Mandatory)
English Description:
Context: FxAsianFeature (complex type)
If one rateObsevation/rate exists, then rateObservationQuoteBasis must exist
XPath Description:
Context: FxAsianFeature
[exists(rateObsevation/rate)]
exists(rateObservationQuoteBasis)
Test cases: [Invalid]
fx-49 (Mandatory)
English Description:
Context: FxSwapLeg (complex type)
If exchangedCurrency1/paymentAmount/currency and exchangedCurrency2/paymentAmount/currency have the same-currency-scheme, then exchangedCurrency1/paymentAmount/currency must not be equal to exchangedCurrency2/paymentAmount/currency
XPath Description:
Context: FxSwapLeg
[same-currency-scheme((exchangedCurrency1/paymentAmount/currency,exchangedCurrency2/paymentAmount/currency))]
exchangedCurrency1/paymentAmount/currency ne exchangedCurrency2/paymentAmount/currency
Test cases: [Invalid]
fx-50 (Mandatory)
English Description:
Context: FxSwapLeg (complex type)
If currency1ValueDate exists, then currency1ValueDate must not be equal to currency2ValueDate.
XPath Description:
Context: FxSwapLeg
[exists(currency1ValueDate)]
currency1ValueDate ne currency2ValueDate
Comment: This rule is similar in its implementation to the rule fx-20, but used for a different type of FX product.
Test cases: [Invalid]
fx-51 (Mandatory)
English Description:
Context: FxSwapLeg (complex type)
If cashSettlement exists, then exchangeRate/forwardPoints must exist
XPath Description:
Context: FxSwapLeg
[exists(cashSettlement)]
exists(exchangeRate/forwardPoints)
Test cases: [Invalid]
fx-52 (Mandatory)
English Description:
Context: Trade (complex type)
If fxOption/americanExercise exists, then fxOption/americanExercise/expiryDate must be after tradeHeader/tradeDate
XPath Description:
Context: Trade
[exists(fxOption/americanExercise)]
fxOption/americanExercise/expiryDate gt tradeHeader/tradeDate
Test cases: [Invalid]
fx-53 (Mandatory)
English Description:
Context: Trade (complex type)
If fxDigitalOption/americanExercise exists, then fxDigitalOption/americanExercise/expiryDate must be after tradeHeader/tradeDate
XPath Description:
Context: Trade
[exists(fxDigitalOption/americanExercise)]
fxDigitalOption/americanExercise/expiryDate gt tradeHeader/tradeDate
Test cases: [Invalid]

#### Deprecated rules

#### Removed rules

fx-1 (Mandatory)
REMOVED: ExchangeRate; Description: rate must be positive. Rationale for removal: fx-1 is not needed. In 5.x redesign model, rate is of type PositiveDecimal.
fx-2 (Mandatory)
REMOVED: ExchangeRate; Description: If forwardPoints exists, then spotRate must exist. Rationale for removal: fx-2 is not needed. 5.x redesigned model has stricter grammar - spotRate and forwardRate are grouped in optional sequence where spotRate is required.
fx-4 (Mandatory)
REMOVED: ExchangeRate; Description: If sideRates/baseCurrency, quotedCurrencyPair/currency1 and quotedCurrencyPair/currency2 have the same same-currency-scheme, then sideRates/baseCurrency is not equal to the values of both quotedCurrencyPair/currency1 and quotedCurrencyPair/currency2 Rationale for removal: fx-4 is not needed. 5.x redesigned model has a new CrossRate structure for which the new rules are created.
fx-5 (Mandatory)
REMOVED: ExchangeRate; Description: If sideRates/currency1SideRate/currency and quotedCurrencyPair/currency1 have the same-currency-scheme, then sideRates/currency1SideRate/currency must be equal to quotedCurrencyPair/currency1 Rationale for removal: fx-5 is not needed. 5.x redesigned model has a new CrossRate structure for which the new rules are created.
fx-6 (Mandatory)
REMOVED: ExchangeRate; Description: If sideRates/currency2SideRate/currency and quotedCurrencyPair/currency2 have the same-currency-scheme, then sideRates/currency2SideRate/currency must be equal to quotedCurrencyPair/currency2 Rationale for removal: fx-6 is not needed. 5.x redesigned model has a new CrossRate structure for which the new rules are created.
fx-7 (Mandatory)
REMOVED: FxAmericanTrigger; Description: triggerRate must be positive. Rationale for removal: fx-7 is not needed. In 5.x redesign model, triggerRate is of type PositiveDecimal.
fx-13 (Mandatory)
REMOVED: FxAverageRateOption; Description: If averageRateObservationDate exists, then each observedRates/observationDate must match one of the dates defined by averageRateObservationDate/observationDate. Rationale for removal: fx-13 does not make any sense in the 5.x redesigned model where observationDate and observedRate/observationDate are combined within FxAverageRateObservation complex type under rateObsevation/date.
fx-15 (Mandatory)
REMOVED: FxBarrierOption; Description: If spotRate exists, then spotRate must be positive. Rationale for removal: fx-15 is not needed. In 5.x redesign model, spotRate is of type PositiveDecimal.
fx-16 (Mandatory)
REMOVED: FxDigitalOption; Description: If spotRate exists, then spotRate must be positive. Rationale for removal: fx-16 is not needed. In 5.x redesign model, touch/spotRate is of type PositiveDecimal.
fx-17 (Mandatory)
REMOVED: FxEuropeanTrigger; Description: triggerRate must be positive. Rationale for removal: fx-17 is not needed. In 5.x redesign model, triggerRate is of type PositiveDecimal.
fx-24 (Mandatory)
REMOVED: FxStrikePrice; Description: rate must be positive. Rationale for removal: fx-24 is not needed. In 5.x redesign model, rate is of type PositiveDecimal.
fx-25 (Mandatory)
REMOVED: FxSwap; Description: Two or more fxSingleLeg elements must exist. Rationale for removal: fx-25 is not needed. In 5.x redesign model, the FxSwap component allows only two legs: nearLeg/FxSwapLeg and farLeg/FxSwapLeg.
fx-28 (Mandatory)
REMOVED: SideRate; Description: rate must be positive. Rationale for removal: fx-28 is not needed. In 4.x the rate was type of xsd:decimal and then used a validation rule to restrict rate value to positive. In 5.x redesign model, the schema controls its value eliminating the rule fx-28.
fx-29 (Mandatory)
REMOVED: SideRate; Description: If forwardPoints exists, then spotRate must exist. Rationale for removal: fx-29 is not needed. In 5.x redesigned model has stricter grammar - spotRate and forwardRate are grouped in optional sequence where spotRate is required, eliminating the rule fx-29.
fx-34 (Mandatory)
REMOVED: TermDeposit; Description: principal/amount must be positive. Rationale for removal: fx-34 is not needed. In 4.x principal/amount was of type xsd:decimal and then used a validation rule to restrict principal/amount value to positive. In 5.x redesign model, the schema controls its value eliminating the rule fx-34.
fx-35 (Mandatory)
REMOVED: TermDeposit; Description: fixedRate must be positive. Rationale for removal: fx-35 is not needed. In 5.x redesign model, fixedRate is of type PositiveDecimal.
fx-36b (Mandatory)
REMOVED: Contract; Description: If fxAverageRateOption exists, then fxAverageRateOption/expiryDateTime/expiryDate must be after header/contractDate. Rationale for removal: fx-36b is not needed. In 5.x , Contract has been removed.
fx-37 (Mandatory)
REMOVED: Trade; Description: If fxBarrierOption exists, then fxBarrierOption/expiryDateTime/expiryDate must be after tradeHeader/tradeDate. Rationale for removal: fx-37 is not needed. In 5.x redesign model, this rule is covered under rule fx-36 and a new rule fx-52 for fxOption/americanExercise/expiryDate.
fx-37b (Mandatory)
REMOVED: Contract; Description: If fxBarrierOption exists, then fxBarrierOption/expiryDateTime/expiryDate must be after header/contractDate. Rationale for removal: fx-37b is not needed. In 5.x , Contract has been removed.
fx-38b (Mandatory)
REMOVED: Contract; Description: If fxDigitalOption exists, then fxDigitalOption/expiryDateTime/expiryDate must be after header/contractDate. Rationale for removal: fx-38b is not needed. In 5.x , Contract has been removed.
fx-39b (Mandatory)
REMOVED: Contract; Description: If fxSingleLeg exists, then the value of fxSingleLeg/valueDate or the value of both fxSingleLeg/currency1ValueDate and fxSingleLeg/currency2ValueDate must be after header/contractDate. Rationale for removal: fx-39b is not needed. In 5.x , Contract has been removed.
fx-40b (Mandatory)
REMOVED: Contract; Description: The value of all fxSwap/fxSingleLeg/valueDate, fxswap/fxSingleLeg/currency1ValueDate and fxSwap/fxSingleLeg/currency2ValueDate instances must be after header/contractDate. Rationale for removal: fx-40b is not needed. In 5.x , Contract has been removed.
fx-41 (Mandatory)
REMOVED: FxBarrier; Description: triggerRate must be positive. Rationale for removal: fx-41 is not needed. In 5.x redesign model, triggerRate is of type PositiveDecimal.
fx-42 (Mandatory)
REMOVED: FxAverageRateOption; Description: The value of each averageRateObservationDate/observationDate must be unique. Rationale for removal: fx-42 is not needed: As per 5.1 Redesign model, it is covered under fx-11 rule.
fx-43 (Mandatory)
REMOVED: FxAverageRateOption; Description: If putCurrencyAmount and callCurrencyAmount have the same-currency-scheme, then putCurrencyAmount/currency must not be equal to callCurrencyAmount/currency. Rationale for removal: fx-43 is not needed: 5.1 Redesign model combines vanilla and averaging options, therefore rule fx-43 covering averaging option is eliminated in favor of rule fx-23.
fx-44 (Mandatory)
REMOVED: FxAverageRateOption; Description: If fxOptionPremium exists, then buyerPartyReference/@href must be equal to fxOptionPremium/payerPartyReference/@href and sellerPartyReference/@href must be equal to fxOptionPremium/receiverPartyReference/@href. Rationale for removal: fx-44 is not needed: 5.1 Redesign model combines vanilla and averaging options, therefore rule fx-44 covering averaging option is eliminated in favor of rule fx-22.
fx-46 (Mandatory)
REMOVED: SideRates; Description: currency1SideRate/sideRateBasis is equal to either "BaseCurrencyPerCurrency1" or "Currency1PerBaseCurrency". Rationale for removal: fx-46 is not needed: 5.1 Redesign model does not use sideRateBase enumeration, therefore rule fx-46 is no longer needed.
fx-47 (Mandatory)
REMOVED: SideRates; Description: currency2SideRate/sideRateBasis is equal to either "BaseCurrencyPerCurrency2" or "Currency2PerBaseCurrency". Rationale for removal: fx-47 is not needed: 5.1 Redesign model does not use sideRateBase enumeration, therefore rule fx-47 is no longer needed.