IMC Low-Latency Challenge
1 Introduction
Welcome to the IMC Low-Latency Challenge! In this challenge, you have to design a high-
performance trading system. Speed and accuracy both matter, and there is no perfect solution.
The higher your score is, the better!
2 Black–Scholes Formula
A call option is a financial contract that gives its owner the right to buy an asset (e.g. a stock)
at a fixed price on a future date. The Black–Scholes formula is a mathematical model that
estimates the price of an option, given many different inputs.
The price of the call option is:
C = S · N (d1 ) − Ke−rT · N (d2 )
where:
ln(S/K) + (r + 21 σ 2 )T √
d1 = √ , d2 = d1 − σ T
σ T
S: underlying asset price
K: strike price
T : time to maturity (in years)
r: risk-free interest rate
σ: volatility
N (·): standard normal cumulative distribution function, see Normal Distribution - Wikipedia
(You do not need to derive or deeply understand these formulas for the challenge.)
3 Problem Statement
You are designing an execution system at IMC. The execution system knows a list of options
that we want to trade, and tries to calculate accurate prices for as many options as possible. For
each option, given the inputs of the Black-Scholes formula, it is possible to calculate the price of
the option. This execution system is responsible for collecting inputs from other systems, and
finally sending a price to the exchange for trading.
For the execution system, here are the inputs:
• S: underlying asset price — this updates frequently, and the updates come in the form of
a ParameterUpdate input.
1
• K: strike price — this is constant for an option, and is provided when registering an option
on startup in the form of an Option input.
• T : time to expiry in years (TTE) — this is constant for an option, and is provided when
registering an option on startup in the form of an Option input.
• r: risk-free interest rate — this is a hard-coded constant for all options, with the value
0.04.
• σ: volatility — this updates infrequently, and the updates come in the form of a ParameterUpdate
input.
Each time you receive a ParameterUpdate, you may return a list of Valuations, which
represent your best guess of the price of options. Note that you may price any subset of the
total options available — it may not always be in your best interest to price an option. (It’s
easy to lose money in the stock market if your valuation is wrong!).
3.1 About Volatility
In practice, asset price updates are easier to calculate, while volatility updates are harder. Even
though both parameters are constantly changing, our execution system may not always know
the latest volatility.
For example, on one option, you could receive updates in this order: U1, V1, U2, U3, U4,
V2. This means you received an underlying update, then a volatility update, then 3 underlying
updates before the next volatility update. During the two volatility updates, the vol could still
change in reality, only our trading system is not fast enough to calculate it.
4 Scoring
When you send a price for an option, a score is calculated. While the exact scoring function is
not revealed, here are some characteristics:
• The grader knows IMC’s price for the option. The closer you are to IMC’s price, the higher
your score is, and the farther you are, the lower your score is.
• If your price is farther than some threshold to IMC’s price, you start losing money — at
that point it would have been better to not send a valuation at all!
• Some options have more people trading, so the amount of money that can be gained (or
lost!) in them is larger than other options.
To help you further, when you submit some Valuations, the next time, the score of those
valuations will be given to you. You may use this score as you wish (or ignore it completely!).
2
5 Implementation
You need to implement a program that conforms to this API (included in [Link]):
1 # pragma once
2 # include < vector >
3
4 struct ParameterUpdate {
5 char type ;
6 double value ;
7 int instrumentId ;
8 };
9
10 struct Valuation {
11 int optionId ;
12 double price ;
13 };
14
15 struct Option {
16 int id ;
17 int underlyingId ;
18 int strike ;
19 double tte ;
20 };
21
22 struct Score {
23 int optionId ;
24 double profit ;
25 };
26
27 class ISolution {
28 public :
29 virtual ~ ISolution () = default ;
30
31 virtual void registerOption ( const Option & option ) = 0;
32 virtual std :: vector < Valuation > process (
33 const ParameterUpdate & update ,
34 const std :: vector < Score >& previousScores
35 ) = 0;
36 };
37
38 ISolution * createSolution () ;
5.1 Constraints
• You will receive at most 5 registerOption calls.
• You will receive at most 106 process calls.
There are 6 test cases. For each test case, your code will be given 1 second to execute,
beyond which it will be terminated.
5.2 ParameterUpdate
• type may be ‘U’ or ‘V’. ‘U’ means asset price (underlying price) update, and ‘V’ means
volatility update.
• value is the updated value of the type mentioned.
• instrumentId is the optionId if it’s a volatility update, and the underlyingId if it’s an
underlying price update.
3
5.3 Grader Interaction
The grader interacts with your program as follows:
1. First, for every option in the test case, the registerOption method is called.
2. Finally, for every ParameterUpdate, the process method is called. This also gives you
the score of the previous Valuations you sent.
6 Starter Template
Use the starter template given in the [Link] provided. It is recommended to build on
top of this template by implementing the two methods in the Solution class. You can modify
the main method to create your own test cases / interaction, but you only need to submit the
cpp file with the Solution class.
To test, compile using:
1 g ++ - std = c ++20 test_main . cpp solution_template . cpp -o main
And then run using:
1 ./ main
7 Execution Environment
Your code is compiled on a Linux VM with this command:
1 g ++ - std = c ++20 - O3 < submission_path >
• The VM has 2 CPUs and 8 GB RAM.
• Your code may spend no more than 1 second on each test case. After 1 second elapses,
the program will automatically terminate — and the score you have gained so far will be
added to the total score.
• There are 6 test cases, in increasing order of difficulty.
8 Sample Interaction
1 Grader : registerOption ({1 , 100 , 70 , 0.05}) ;
2 Grader : process ({ ’U ’ , 74 , 100} , {})
3 Solution : return {}
4 Grader : process ({ ’V ’ , 0.52 , 1} , {})
5 Solution : return {{1 , 5.80}}
6 Grader : process ({ ’U ’ , 75 , 100} , {{1 , 25}})
7 Solution : return {{1 , 6.53}}
1. The grader tells you to register an option with ID=1, underlyingID=100, strike=70,
TTE=0.05.
2. The grader tells you that the latest price of the underlying with ID=100 is 74. Since you
have not sent any valuations yet, the grader sends an empty list for previousScores.
3. You don’t send any valuation message yet, returning an empty list.
4
4. The grader tells you that the latest volatility of the option with ID=1 is 0.52. Since you
have not sent any valuations yet, the grader sends an empty list for previousScores.
5. You now compute the Black-Scholes price using all the inputs provided. According to your
algorithm, the price comes out to be approximately 5.80. So you return {{1, 5.80}}.
6. The grader sends you the next update, saying that the price of the underlying with ID=100
has now changed to 75. The grader also tells you that for your previous valuation, you got
a score of 25.
7. You recalculate the price of the option and return 6.53 for optionID=1.
9 Submissions
You may submit using this webpage.
• Use the token provided to you. Do not share that token with anyone else!
• You only need to submit one CPP file — the implementation file. You do not need to
submit the header file or your test/runner files. The CPP file you submit should NOT
have a main method.
• Submissions are rate-limited. You may submit only once every 30 seconds. This limit may
be changed during the contest time.
• After submission, wait 1–2 minutes to get the latest score using the Retrieve past scores
button.