Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Behaviour of cross asset simulation configuration (FX) #235

Open
rkapl123 opened this issue May 13, 2024 · 2 comments
Open

Behaviour of cross asset simulation configuration (FX) #235

rkapl123 opened this issue May 13, 2024 · 2 comments

Comments

@rkapl123
Copy link
Contributor

rkapl123 commented May 13, 2024

After trying a base currency change, I've discovered some irritating behaviour in the simulation configuration validity checking:
I tried to change the base currency to USD by simply changing the BaseCurrency tag in both CrossAssetModel and Market to USD:
image
image

However, unless the FIRST currency is not set to the base currency, ORE fails checking this config by passing back an error occurred: currency mismatch between IR and FX config vectors as an error. So this is actually working:
image
image

I'm tempted to add a detailed explanation in the user guide, but I'm not sure whether this behaviour shouldn't be rather treated as a bug (as the definition of the currency sequence should be free as long as it is consistent between CrossAssetModel and Market)...

@pcaspers
Copy link
Collaborator

Absolutely, a bug or at least an unnecessary restriction. We should fix this.

@rkapl123
Copy link
Contributor Author

rkapl123 commented May 20, 2024

Thanks for checking, after looking into the source, I found that actually the currencies defined in the Market section are irrelevant (at least in their order) for the Cross asset model. The problem is only within the CrossAssetModel node.

Checking the validation code, considering the build methods, it is assumed that irConfigs_[0] contains the domestic currency, meaning it has to come first:

    for (Size i = 0; i < fxConfigs_.size(); ++i)
        QL_REQUIRE(fxConfigs_[i]->foreignCcy() == irConfigs_[i + 1]->ccy(),
                   "currency mismatch between IR and FX config vectors");
....

as the buildIrConfigs method builds all currencies nodes

void CrossAssetModelData::buildIrConfigs(std::map<std::string, boost::shared_ptr<IrModelData>>& irDataMap) {
    irConfigs_.resize(currencies_.size());
    for (Size i = 0; i < currencies_.size(); i++) {
        string ccy = currencies_[i];
        std::string ccyKey;
        for (auto const& d : irDataMap) {
            if (d.second->ccy() == ccy) {
                QL_REQUIRE(ccyKey.empty(), "CrossAssetModelData: duplicate ir config for ccy " << ccy);
                ccyKey = d.first;
            }
        }
        if (!ccyKey.empty())
            irConfigs_[i] = irDataMap.at(ccyKey);
        else { // copy from default
            LOG("IR configuration missing for currency " << ccy << ", using default");
....

and the buildFxConfigs method skips the node where the currency is the domestic currency:

void CrossAssetModelData::buildFxConfigs(std::map<std::string, boost::shared_ptr<FxBsData>>& fxDataMap) {
    for (Size i = 0; i < currencies_.size(); i++) {
        string ccy = currencies_[i];
        if (ccy == domesticCurrency_)
            continue;
        if (fxDataMap.find(ccy) != fxDataMap.end())
            fxConfigs_.push_back(fxDataMap[ccy]);
        else { // copy from default
            LOG("FX configuration missing for foreign currency " << ccy << ", using default");
            if (fxDataMap.find("default") == fxDataMap.end()) {

Considering the validation code above, this can only work if the first currency is the domestic currency, if it is not, then the fxConfigs_ vector will always miss the domestic currency at the wrong place.

I don't have a clever idea that generalizes this without probably breaking a lot of other dependent code (e.g. a possibility might be to move the skipping of the domestic currency in buildFxConfigs to a later place and compare fxConfigs_[i]->foreignCcy() == irConfigs_[i]->ccy()).

I think a better and simpler solution (in addition to documenting this in the user guide) might be to simply assert that the first currency has to be the domestic currency and failing if it is not, e.g.:

    QL_REQUIRE(fxConfigs_.size() == irConfigs_.size() - 1, "inconsistent number of FX data provided");
    QL_REQUIRE( irConfigs_[0]->ccy() == domesticCurrency_,"first currency defined has to be the domestic currency");
    for (Size i = 0; i < fxConfigs_.size(); ++i)
        QL_REQUIRE(fxConfigs_[i]->foreignCcy() == irConfigs_[i + 1]->ccy(),
                   "currency mismatch between IR and FX config vectors");
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants