public Candle SubCandle(DateTimeOffset now, ETimeFrame time_frame) { // Interpolate the latest candle to determine the spot price var t = Math_.Frac(Timestamp, now.Ticks, Timestamp + Misc.TimeFrameToTicks(1.0, time_frame)); return(SubCandle(Math_.Clamp(t, 0.0, 1.0))); }
/// <summary> /// Emulate the behaviour of the update thread by notifying of /// 'DataChanged' as the simulation time advances.</summary> public void SimulationUpdate(bool force_invalidate) { // Don't actually modify the DB. var now = Model.UtcNow.Ticks; // Determine the update type by comparing the sim time to the time stamp of the current candle. // This is a "new" candle the sim time is within one TimeFrame period after the current candle. // This is an update to the "latest" candle if within a TimeFrame period of the current candle. // Otherwise it's an unknown range. var tf_ticks = Misc.TimeFrameToTicks(1.0, TimeFrame); var update_type = m_current == null || force_invalidate ? DataEventArgs.EUpdateType.Range : now.Within(m_current.Timestamp + 1 * tf_ticks, m_current.Timestamp + 2 * tf_ticks) ? DataEventArgs.EUpdateType.New : now.Within(m_current.Timestamp, m_current.Timestamp + 1 * tf_ticks) ? DataEventArgs.EUpdateType.Current : DataEventArgs.EUpdateType.Range; // Record the last time data was received LastUpdatedUTC = Model.UtcNow; // Update/Invalidate cached values switch (update_type) { case DataEventArgs.EUpdateType.New: { // Invalidate 'm_current' so that the next candle is read from the DB. // Don't change m_total, m_newest, or m_oldest, they are constant during simulations. m_current = null; var count = CountTo(now); OnDataChanged(new DataEventArgs(update_type, this, new RangeI(count - 1, count), Current)); break; } case DataEventArgs.EUpdateType.Current: { // Nothing to invalidate. 'Current' does sub candle interpolation in back-testing mode. var count = CountTo(now); OnDataChanged(new DataEventArgs(update_type, this, new RangeI(count - 1, count), Current)); break; } default: { // 'now' has moved to an unknown time. Just invalidate 'm_current' m_current = CurrentAt(now); OnDataChanged(new DataEventArgs(this)); break; } } }
/// <summary>Returns the age of this candle as a normalised fraction of the time frame</summary> public double Age(Instrument instr) { var one = Misc.TimeFrameToTicks(1.0, instr.TimeFrame); var age_ticks = Model.UtcNow.Ticks - Timestamp; if (age_ticks < 0) { return(0.0); } if (age_ticks > one) { return(1.0); } return(Math_.Frac(0.0, age_ticks, one)); }
/// <summary>Add a candle value to the database</summary> private void Add(ETimeFrame tf, Candle candle) { // Sanity check Debug.Assert(candle.Valid()); Debug.Assert(candle.Timestamp != 0); Debug.Assert(tf != ETimeFrame.None); Debug.Assert(tf == TimeFrame); if (Model.BackTesting) { throw new Exception("Should not be adding candles to the DB while back testing"); } // This is a new candle if it's time stamp is one TimeFrame period after the Newest candle. // This is an update to the latest candle if within a TimeFrame period of the Newest candle. // Otherwise it's an unknown range. var tf_ticks = Misc.TimeFrameToTicks(1.0, TimeFrame); var update_type = Newest == null ? DataEventArgs.EUpdateType.Range : candle.Timestamp == Newest.Timestamp + tf_ticks ? DataEventArgs.EUpdateType.New : candle.Timestamp.Within(Newest.Timestamp, Newest.Timestamp + tf_ticks) ? DataEventArgs.EUpdateType.Current : DataEventArgs.EUpdateType.Range; // Insert the candle into the database UpsertCandle(candle); // Record the last time data was received LastUpdatedUTC = Model.UtcNow; // Update/Invalidate cached values switch (update_type) { case DataEventArgs.EUpdateType.New: { m_newest = candle; m_current = m_newest; m_total += 1; break; } case DataEventArgs.EUpdateType.Current: { m_newest.Update(candle); m_current = m_newest; break; } default: { // This must be an update to some random candle in the middle. // Just invalidate the cached values. Shouldn't ever happen really. m_total = null; m_newest = null; m_oldest = null; m_current = null; break; } } // Notify data added/changed OnDataChanged(new DataEventArgs(update_type, this, new RangeI(Count - 1, Count), candle)); }
public TimeFrameTime(double tf_units, ETimeFrame tf) : this(Misc.TimeFrameToTicks(tf_units, tf), tf) { }