/// <summary>Return the chart X axis value for a given time</summary> public double ChartXValue(TFTime time) { //' X-Axis: -ve --- 0 ---- +ve ' //' Idx: <0 0 >0 ' //' past now future' // If the time is a point in the future, return the number of candles assuming no gaps if (time.ExactTicks >= Latest.Timestamp) { return(new TFTime(time.ExactTicks - Latest.Timestamp, TimeFrame).ExactTF); // positive number, cos it's in the future } // If the time is a point in the past beyond our history, return the number of candles assuming no gaps if (time.ExactTicks <= Oldest.Timestamp) { return(-(Count + new TFTime(Oldest.Timestamp - time.ExactTicks, TimeFrame).ExactTF)); // negative, cos it's in the past } // Get the index into the past var idx = IndexAt(time); // Lerp between the timestamps of the candles on either side of 'idx' // Candles should exist because we know we're in the time range of the candle data. var c0 = this[idx]; Debug.Assert(c0 != null); var c1 = this[idx + 1]; Debug.Assert(c1 != null); var frac = Maths.Frac(c0.Timestamp, time.ExactTicks, c1.Timestamp); Debug.Assert(frac >= 0.0 && frac <= 1.0); return(idx + frac); }
/// <summary>Convert a time frame time range to an index range. (Indices in the range (-Count, 0])</summary> public Range TimeToIndexRange(TFTime time_min, TFTime time_max) { Debug.Assert(time_min <= time_max); var idx_min = IndexAt(time_min); var idx_max = IndexAt(time_max); return(new Range(idx_min, idx_max)); }
/// <summary>Return the index of the candle at or immediately before 'time_stamp'. Note: the returned indices will be in the range (-Count, 0]</summary> public int IndexAt(TFTime time_stamp) { var ticks = time_stamp.ExactTicks; // If the time stamp is within the cached range, binary search the cache for the index position if (CachedTimeRange.Contains(ticks)) { var idx = m_cache.BinarySearch(x => x.Timestamp.CompareTo(ticks)); if (idx < 0) { idx = ~idx; } return((m_index_range.Begi + idx) + FirstIdx); } // Otherwise use database queries to determine the index else { var sql = Str.Build("select count(*)-1 from ", TimeFrame, " where [", nameof(Candle.Timestamp), "] <= ? order by [", nameof(Candle.Timestamp), "]"); var idx = m_db.ExecuteScalar(sql, 1, new object[] { ticks }); return(idx + FirstIdx); } }
protected override void UpdateGfxCore() { // Find the index range in the Instrument history that 'Order' maps to var t0 = new TFTime(Order.EntryTimeUTC.Ticks, Instrument.TimeFrame); var t1 = new TFTime(Order.ExitTimeUTC.Ticks, Instrument.TimeFrame); var range = Instrument.TimeToIndexRange(t0, t1); // If the expiry is in the future, add on the expected number of candles var t2 = t1.ExactUTC > Instrument.Latest.TimestampUTC ? (int)new TFTime(t1.ExactUTC - Instrument.Latest.TimestampUTC, Instrument.TimeFrame).IntgTF : 0; // Determine the width and position of the order var x = (float)(range.Begi - range.Endi); var w = (float)(range.Sizei + t2); // Get the entry price, stop loss, and take profit values var ep = (float)Order.EntryPrice; var sl = (float)Order.StopLossRel; var tp = (float)Order.TakeProfitRel; // Create graphics for the order switch (Order.TradeType) { default: { Debug.Assert(false, "Unknown trade type"); Gfx = null; break; } case ETradeType.None: { Gfx = null; break; } case ETradeType.Short: case ETradeType.Long: { var sign = Order.TradeType == ETradeType.Long ? +1 : -1; var selected = Selected || Hovered; var alpha = selected ? 0.5f : 0.25f; var z = ChartUI.Z.Trades + (selected ? 0.0001f : 0f); var sl_col = Settings.Chart.TradeLossColour.Alpha(alpha); var tp_col = Settings.Chart.TradeProfitColour.Alpha(alpha); var ep_col = Color.DarkBlue; var line_col = Order.TradeType == ETradeType.Long ? Settings.UI.BullishColour.Alpha(0x60) : Settings.UI.BearishColour.Alpha(0x60); var xmin = selected ? (float)Chart.XAxis.Min : x - 0; var xmax = selected ? (float)Chart.XAxis.Max : x + w; m_vbuf.Clear(); m_ibuf.Clear(); m_nbuf.Clear(); var V = 0U; var I = 0U; // Take profit area if (tp > 0) { var v = m_vbuf.Count; var y0 = sign > 0 ? Math.Max(ep, ep - sl) : ep - tp; var y1 = sign > 0 ? ep + tp : Math.Min(ep, ep + sl); m_vbuf.Add(new View3d.Vertex(new v4(x, y0, z, 1), tp_col.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(x + w, y0, z, 1), tp_col.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(x, y1, z, 1), tp_col.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(x + w, y1, z, 1), tp_col.ToArgbU())); m_ibuf.AddRange(new[] { (ushort)v, (ushort)(v + 1), (ushort)(v + 3), (ushort)(v + 3), (ushort)(v + 2), (ushort)v }); } // Stop loss area if (sl > 0) { var v = m_vbuf.Count; var y0 = sign > 0 ? ep - sl : Math.Max(ep, ep - tp); var y1 = sign > 0 ? Math.Min(ep, ep + tp) : ep + sl; m_vbuf.Add(new View3d.Vertex(new v4(x, y0, z, 1), sl_col.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(x + w, y0, z, 1), sl_col.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(x, y1, z, 1), sl_col.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(x + w, y1, z, 1), sl_col.ToArgbU())); m_ibuf.AddRange(new[] { (ushort)v, (ushort)(v + 1), (ushort)(v + 3), (ushort)(v + 3), (ushort)(v + 2), (ushort)v }); } m_nbuf.Add(new View3d.Nugget(View3d.EPrim.TriList, View3d.EGeom.Vert | View3d.EGeom.Colr, V, (uint)m_vbuf.Count, I, (uint)m_ibuf.Count, true)); V = (uint)m_vbuf.Count; I = (uint)m_ibuf.Count; // Entry Price line { var v = m_vbuf.Count; m_vbuf.Add(new View3d.Vertex(new v4(xmin, ep, z, 1), Color.DarkBlue.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(xmax, ep, z, 1), Color.DarkBlue.ToArgbU())); m_ibuf.AddRange(new[] { (ushort)v, (ushort)(v + 1) }); } // Take Profit line { var v = m_vbuf.Count; m_vbuf.Add(new View3d.Vertex(new v4(xmin, ep + sign * tp, z, 1), Color.DarkGreen.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(xmax, ep + sign * tp, z, 1), Color.DarkGreen.ToArgbU())); m_ibuf.AddRange(new[] { (ushort)v, (ushort)(v + 1) }); } // Stop Loss line { var v = m_vbuf.Count; m_vbuf.Add(new View3d.Vertex(new v4(xmin, ep - sign * sl, z, 1), Color.DarkRed.ToArgbU())); m_vbuf.Add(new View3d.Vertex(new v4(xmax, ep - sign * sl, z, 1), Color.DarkRed.ToArgbU())); m_ibuf.AddRange(new[] { (ushort)v, (ushort)(v + 1) }); } m_nbuf.Add(new View3d.Nugget(View3d.EPrim.LineList, View3d.EGeom.Vert | View3d.EGeom.Colr, V, (uint)m_vbuf.Count, I, (uint)m_ibuf.Count, true)); // Create the geometry Gfx = new View3d.Object("Order", 0xFFFFFFFF, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray()); break; } } base.UpdateGfxCore(); }
/// <summary>Enumerate the candles within a time range (given in time-frame units)</summary> public IEnumerable <Candle> CandleRange(TFTime time_min, TFTime time_max) { var range = TimeToIndexRange(time_min, time_max); return(CandleRange(range.Begi, range.Endi)); }
public TFTime(TFTime tft, ETimeFrame tf) : this(tft.m_ticks, tf) { }
public bool Equals(TFTime rhs) { return(m_ticks == rhs.m_ticks && m_time_frame == rhs.m_time_frame); }