2

I am modeling a ship that has contracts. Each contract can either be a fixed rate contract which pays a set fixed amount every day or a market index contract which pays an amount that varies based on a market index.

I hope to run simulations on each ship where I would provide required information on what the market index is in the future to calculate the earnings from each contract.

I had approached this as follows using rust where a ship has a vector of ContractLike contracts:

struct Ship {
        pub name: String,
        pub contracts: Vec<Box<dyn ContractLike>>,
    }

pub struct FixedContract {
        dayrate: i32,
        start_date: NaiveDate, 
        end_date: NaiveDate,
 }
pub struct MarketIndexContract {
        // no fixed dayrate since function of index price which is not known
        // should I store the MarketIndex data here?
       start_date: NaiveDate,
       end_date: NaiveDate,
    }

Both contract types however are ContractLike in that they implement the trait ContractedRevenues which tells you how much money is due under the contract between 2 dates (I return it as a vector of ints for each day):

pub trait ContractLike: ContractedRevenues{}
impl<T: ContractedRevenues> ContractLike for T {}
 
pub trait ContractedRevenues {
        fn contracted_revenues(&self, date1: NaiveDate, date2: NaiveDate) -> Vec<i32>;
    }

The problem is that MarketIndexContract needs more than just date1 and date2 to compute the ContractedRevenues.

I was thinking I should store the future Market Index values in the MarketIndexContract struct by changing the MarketIndexContract constructor. Then when I ran each simulation I would re-construct the MarketIndexContracts structs with new future index prices and the ContractedRevenues trait implementation for MarketIndexContracts could get the data from the struct's data member.

The downside, however, is it seems to make the Ship dependent on a simulation existing to construct it. There are uses where I want to use my Ship without there being a simulation. For instance, what if I wanted to query my Ship for how many contracts it has? That use case doesn't depend on a simulation existing (i.e. the future index prices being known).

How best should I approach this design?

2
  • (1) If the ContractedRevenues trait does not fulfil your needs, why are you using this trait? Is this an external requirement? Otherwise, why can't the market index values become another parameter to the contracted_revenues() function? (2) Are all types of contracts known upfront? Consider using an enum instead of a Box<dyn ...> object. Since enums allow access to fields of their variants, you have far more flexibility and are not constrained to the trait's methods.
    – amon
    Apr 30 at 19:16
  • (1) Not a requirement. 100% flexibility on how to design. I originally considered overloading contracted_revenues() but wasn't sure how to make a trait that allows the parameters to change in rust. (2) They are not all known but would be acceptable to lock in to these types. Could you elaborate on how to use an enum here? Assuming you instead have 1 Contract type that accepts an enum in constructor, how would you be able to accept different arguments for contracted_revenues?
    – cpage
    Apr 30 at 20:03
1

Unless I misunderstood, your app is supposed to answer the following question:

Given a set of contractual agreements C, some of which depend on external market data, what would happen in scenarios S1...Sn, where each scenario simulates a different market environment.

Contract information are part of C, i.e. they don't change between scenarios. Market data is specific to a scenario Si. Therefore, they should be kept separate.

At some point, you need to loop over all contracts, regardless of their type, to calculate some value. You need to bring along the market data, in case you need it.

One option is to keep the ContractedValues abstraction, and a separate type for each contract that implements this abstraction. In this case, you add a third parameter to your contracted_revenues method, which the FixedContract simply ignores. This feels kind of OOP-inspired, and is needlessly complex, in my opinion.

By the way: overloading the method with a different number of parameters does not help - how would you know which one to call?

Instead, I would propose to encode the different pricing models directly:


#[derive(...)]
enum PricingModel {
    FixedRate(i32),
    IndexBased,
}

#[derive(...)]
pub struct Contract {
    pricing_model: PricingModel,
    active_period: TimePeriod,
}

impl Contract {
    pub fn fixed_rate(rate: i32) -> Self { ... }
    pub fn index_based() -> Self { ... }

    pub fn contracted_revenues(&self, period: TimePeriod, market_data: &MarketData)-> Vec<i32> {
        match self.pricing_model {
            ...
        }
    }
}

Yes, this is less open to new pricing models - especially by third parties - but those would likely also require additional outside information beside the market data, i.e. it's unlikely they'd fit into your model anyways. It's possible to make that work as well, but everything becomes much more complex.

2
  • Could you elaborate on how you what type of traits you see being derived in your use of #[derive(....)] above?
    – cpage
    May 18 at 19:41
  • 1
    Nothing in particular (Debug, Eq, etc. depending on what you need). They have no relevance for the answer, it's just a habit.
    – doubleYou
    May 27 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.