/// <summary>Generate simulated market depth for 'pair', using 'latest' as the reference for the current spot price</summary> private MarketDepth GenerateMarketDepth(TradePair pair, Candle latest, ETimeFrame time_frame) { // Notes: // - This is an expensive call when back testing is running so minimise allocation, resizing, and sorting. // - Do all calculations using double's for speed. // Get the market data for 'pair'. // Market data is maintained independently to the pair's market data instance because the // rest of the application expects the market data to periodically overwrite the pair's order books. var md = m_depth[pair]; // Get the Q2B (bid) spot price from the candle close. (This is the minimum of the Q2B offers) // The B2Q spot price is Q2B - spread, which will be the maximum of the B2Q offers var spread = latest.Close * m_spread_frac; var best_q2b = latest.Close; var best_b2q = latest.Close - spread; var base_value = (double)(decimal)pair.Base.Value; md.Q2B.Offers.Resize(m_orders_per_book); md.B2Q.Offers.Resize(m_orders_per_book); // Generate offers with a normal distribution about 'best' var range = 0.2 * 0.5 * (best_q2b + best_b2q); for (var i = 0; i != m_orders_per_book; ++i) { var p = range * Math_.Sqr((double)i / m_orders_per_book); md.Q2B.Offers[i] = new Offer(((decimal)(best_q2b + p))._(pair.RateUnits), RandomAmountBase()._(pair.Base)); md.B2Q.Offers[i] = new Offer(((decimal)(best_b2q - p))._(pair.RateUnits), RandomAmountBase()._(pair.Base)); } return(md); decimal RandomAmountBase() { // Generate an amount to trade in the application common currency (probably USD). // Then convert that to base currency using the 'live' value. var common_value = Math.Abs(m_rng.Double(m_order_value_range.Beg, m_order_value_range.End)); var amount_base = (decimal)Math_.Div(common_value, base_value, common_value); return(amount_base); } }