Exemplo n.º 1
0
 /// <summary>Update the price data</summary>
 public static string UpdatePriceData()
 {
     return(Str.Build(
                "insert or replace into PriceData ( ",
                "rowid,",
                "[", nameof(PriceData.AskPrice), "],",
                "[", nameof(PriceData.BidPrice), "],",
                "[", nameof(PriceData.AvrSpread), "],",
                "[", nameof(PriceData.LotSize), "],",
                "[", nameof(PriceData.PipSize), "],",
                "[", nameof(PriceData.PipValue), "],",
                "[", nameof(PriceData.VolumeMin), "],",
                "[", nameof(PriceData.VolumeStep), "],",
                "[", nameof(PriceData.VolumeMax), "])",
                " values (",
                "1,",          // rowid
                "?,",          // AskPrice
                "?,",          // BidPrice
                "?,",          // AvrSpread
                "?,",          // LotSize
                "?,",          // PipSize
                "?,",          // PipValue
                "?,",          // VolumeMin
                "?,",          // VolumeStep
                "?)"           // VolumeMax
                ));
 }
Exemplo n.º 2
0
 /// <summary>Create a table of support and resistance levels</summary>
 public static string SnRLevelsTable()
 {
     return(Str.Build(
                "create table if not exists SnRLevels (\n",
                "[", nameof(SnRLevel.Id), "] text unique,\n",
                "[", nameof(SnRLevel.Price), "] real,\n",
                "[", nameof(SnRLevel.WidthPips), "] real,\n",
                "[", nameof(SnRLevel.MaxTimeFrame), "] int)"
                ));
 }
Exemplo n.º 3
0
 /// <summary>Create a table of candles for a time frame</summary>
 public static string CandleTable(ETimeFrame time_frame)
 {
     return(Str.Build(
                "create table if not exists ", time_frame, " (\n",
                "[", nameof(Candle.Timestamp), "] integer unique,\n",
                "[", nameof(Candle.Open), "] real,\n",
                "[", nameof(Candle.High), "] real,\n",
                "[", nameof(Candle.Low), "] real,\n",
                "[", nameof(Candle.Close), "] real,\n",
                "[", nameof(Candle.Median), "] real,\n",
                "[", nameof(Candle.Volume), "] real)"
                ));
 }
Exemplo n.º 4
0
            /// <summary>Return all the candles in the given time range</summary>
            public IEnumerable <InMsg.CandleData> EnumCandleData(DateTimeOffset t0, DateTimeOffset t1)
            {
                var ts   = "[" + nameof(Candle.Timestamp) + "]";
                var sql  = Str.Build("select * from {0} where ", ts, " >= ? and ", ts, " <= ? order by ", ts);
                var args = new object[] { t0.Ticks, t1.Ticks };

                foreach (var tf in TimeFrames)
                {
                    foreach (var candle in m_db.EnumRows <Candle>(sql.Fmt(tf), 1, args))
                    {
                        yield return(new InMsg.CandleData(SymbolCode, tf, candle));
                    }
                }
            }
Exemplo n.º 5
0
 /// <summary>Reset the log file</summary>
 private void ResetLog()
 {
     using (var log = new StreamWriter(new FileStream(LogFilepath, FileMode.Create, FileAccess.Write, FileShare.Read)))
     {
         log.WriteLine(Str.Build(
                           "Succeeded, ",
                           "TradeType, ",
                           "Profit, ",
                           "RtR, ",
                           string.Join(", ", Features.Select(x => x.Label)),
                           string.Empty));
     }
     m_reset_log = false;
 }
Exemplo n.º 6
0
 /// <summary>Insert a support and resistance level into the DB</summary>
 public static string UpdateSnRLevel()
 {
     return(Str.Build(
                "insert or replace into SnRLevels (",
                "[", nameof(SnRLevel.Id), "],",
                "[", nameof(SnRLevel.Price), "],",
                "[", nameof(SnRLevel.WidthPips), "],",
                "[", nameof(SnRLevel.MaxTimeFrame), "]",
                ") values (",
                "?,",          // Id
                "?,",          // Price
                "?,",          // WidthPips
                "?)"           // MaxTimeFrame
                ));
 }
Exemplo n.º 7
0
 /// <summary>Create a price data table</summary>
 public static string PriceDataTable()
 {
     // Note: this doesn't store the price data history, only the last received price data
     return(Str.Build(
                "create table if not exists PriceData (\n",
                "[", nameof(PriceData.AskPrice), "] real,\n",
                "[", nameof(PriceData.BidPrice), "] real,\n",
                "[", nameof(PriceData.AvrSpread), "] real,\n",
                "[", nameof(PriceData.LotSize), "] real,\n",
                "[", nameof(PriceData.PipSize), "] real,\n",
                "[", nameof(PriceData.PipValue), "] real,\n",
                "[", nameof(PriceData.VolumeMin), "] real,\n",
                "[", nameof(PriceData.VolumeStep), "] real,\n",
                "[", nameof(PriceData.VolumeMax), "] real)"
                ));
 }
Exemplo n.º 8
0
        /// <summary>Add the results of a virtual trade to the log</summary>
        private void LogPrediction(Prediction pred)
        {
            if (m_reset_log)
            {
                ResetLog();
            }

            var trade    = pred.Trade;
            var features = pred.Features;

            using (var log = new StreamWriter(new FileStream(LogFilepath, FileMode.Append, FileAccess.Write, FileShare.Read)))
            {
                log.WriteLine(Str.Build(
                                  trade.Result == Trade.EResult.HitTP ? 1 : 0, ", ",
                                  trade.TradeType, ", ",
                                  (trade.Result == Trade.EResult.HitTP ? trade.PeakProfit : -trade.PeakLoss) * trade.Volume, ", ",
                                  trade.RtR, ", ",
                                  string.Join(", ", features.Select(x => x.Value)),
                                  string.Empty));
            }
        }
Exemplo n.º 9
0
 /// <summary>Insert or replace a candle in table 'time_frame'</summary>
 public static string InsertCandle(ETimeFrame time_frame)
 {
     return(Str.Build(
                "insert or replace into ", time_frame, " (",
                "[", nameof(Candle.Timestamp), "],",
                "[", nameof(Candle.Open), "],",
                "[", nameof(Candle.High), "],",
                "[", nameof(Candle.Low), "],",
                "[", nameof(Candle.Close), "],",
                "[", nameof(Candle.Median), "],",
                "[", nameof(Candle.Volume), "])",
                " values (",
                "?,",          // Timestamp
                "?,",          // Open
                "?,",          // High
                "?,",          // Low
                "?,",          // Close
                "?,",          // Median
                "?)"           // Volume
                ));
 }
Exemplo n.º 10
0
        /// <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);
            }
        }
Exemplo n.º 11
0
        /// <summary>The raw data. Idx = 0 is the oldest, Idx = Count is the latest</summary>
        public Candle this[PosIdx pos_idx]
        {
            get
            {
                Debug.Assert(pos_idx >= 0 && pos_idx < Count);

                // Shift the cached range if needed
                if (!m_index_range.Contains(pos_idx))
                {
                    m_cache.Clear();

                    // Otherwise, reload the cache centred on the requested index
                    var new_range = new Range((long)pos_idx - CacheSize / 2, (long)pos_idx + CacheSize / 2);
                    if (new_range.Beg < 0)
                    {
                        new_range = new_range.Shift(0 - new_range.Beg);
                    }
                    if (new_range.End > Count)
                    {
                        new_range = new_range.Shift(Count - new_range.End);
                    }
                    if (new_range.Beg < 0)
                    {
                        new_range.Beg = 0;
                    }

                    // Populate the cache from the database
                    // Order by timestamp so that the oldest is first, and the newest is at the end.
                    var sql = Str.Build("select * from ", TimeFrame, " order by [", nameof(Candle.Timestamp), "] limit ?,?");
                    m_cache.AddRange(m_db.EnumRows <Candle>(sql, 1, new object[] { new_range.Begi, new_range.Sizei }));
                    m_index_range = new_range;
                }

                return(m_cache[(int)pos_idx - m_index_range.Begi]);
            }
        }
Exemplo n.º 12
0
        /// <summary>Look for predictions with each new data element</summary>
        protected override void UpdateFeatureValues(DataEventArgs args)
        {
            // Require at least 3 candles
            if (Instrument.Count < 3)
            {
                return;
            }

            Features.Clear();

            // Find the approximate candle size
            var msc = Instrument.MedianCandleSize(-100, 0);

            // Get the last few candles
            // Make decisions based on 'B', the last closed candle.
            var A = Instrument[0]; var a_type = A.Type(msc);
            var B = Instrument[-1]; var b_type = A.Type(msc);
            var C = Instrument[-2]; var c_type = A.Type(msc);

            // The age of 'A' (normalised)
            var a_age = Instrument.AgeOf(A, clamped: true);

            // Measure the strength of the trend leading up to 'B' (but not including)
            var preceding_trend = Instrument.MeasureTrend(-5, -1);

            // Opposing trend
            var opposing_trend =
                !c_type.IsIndecision() && !b_type.IsIndecision() &&   // Bodies are a reasonable size
                (C.Sign >= 0) != (B.Sign >= 0);                       // Opposite sign

            // Engulfing: A trend, ending with a reasonable sized body,
            // followed by a bigger body in the opposite direction.
            if ((opposing_trend) &&                                                // Opposing trend directions
                (c_type.IsTrend() && b_type.IsTrend()) &&                          // Both trend-ish candles
                (B.BodyLength > 1.20 * C.BodyLength) &&                            // B is bigger than 120% C
                (Math.Abs(B.Open - C.Close) < 0.05 * B.TotalLength) &&             // B.Open is fairly close to C.Close
                (Math.Abs(preceding_trend) > 0.8) &&                               // There was a trend leading into B
                (Math.Sign(preceding_trend) != B.Sign))                            // The trend was the opposite of B
            {
                Features.Add(new Feature("CandlePattern", B.Sign, Str.Build(
                                             "Engulfing: A trend, ending with a reasonable sized body, followed by a bigger body in the opposite direction.\n",
                                             " C:{0}  B:{1}  A:{2}\n".Fmt(c_type, b_type, a_type),
                                             " Preceding trend: {0}\n".Fmt(preceding_trend),
                                             "")));
                return;
            }

            // Trend, indecision, trend:
            if ((b_type.IsIndecision()) &&                         // A hammer, spinning top, or doji
                (Math.Abs(preceding_trend) > 0.8))                 // A trend leading into the indecision
            {
                // This could be a continuation or a reversal. Need to look at 'A' to decide
                if (!a_type.IsIndecision())                 // If A is not an indecision candle as well
                {
                    // Use the indecision candle total length to decide established trend.
                    // Measure relative to B.BodyCentre.
                    // The stronger the indication, the least old 'A' has to be
                    var dist = Math.Abs(A.Close - B.BodyCentre);
                    var frac = Maths.Frac(B.TotalLength, dist, B.TotalLength * 2.0);
                    if (a_age >= 1.0 - Maths.Frac(0.0, dist, 1.0))
                    {
                        var reversal = Math.Sign(preceding_trend) != A.Sign;
                        Features.Add(new Feature("CandlePattern", A.Sign, Str.Build(
                                                     "Hammer, Spinning top, or doji:  and a trend leading into the indecision\n",
                                                     " C:{0}  B:{1}  A:{2}\n".Fmt(c_type, b_type, a_type),
                                                     " Preceding trend: {0}\n".Fmt(preceding_trend),
                                                     "")));
                        return;
                    }
                }
            }

            //// Tweezers
            //if ((C.Type == Candle.EType.MarubozuWeakening && B.Type == Candle.EType.MarubozuStrengthening) &&
            //	(Math.Abs(preceding_trend) > 0.8))
            //{
            //	Forecast = B.Sign > 0 ? TradeType.Buy : TradeType.Sell;
            //	Comments = Str.Build(
            //		"Tweezers pattern",
            //		" C:{0}  B:{1}  A:{2}\n".Fmt(c_type, b_type, a_type),
            //		" Preceding trend: {0}\n".Fmt(preceding_trend),
            //		"");
            //	return;
            //}

            //// Continuing trend
            //if ((Math.Abs(preceding_trend) > 0.8) && // Preceding trend
            //	(B.IsTrend && B.Sign == Math.Sign(preceding_trend)))
            //{
            //	Forecast = B.Sign > 0 ? TradeType.Buy: TradeType.Sell;
            //	Comments = "Continuing trend";
            //	return;
            //}

            //// Consolidation
            //if ((Math.Abs(preceding_trend) < 0.5) &&
            //	!B.IsIndecision &&
            //	!B.IsTrend)
            //{
            //	Forecast = null;
            //	Comments = "Consolidation, no trend";
            //	return;
            //}

            // no idea
            Features.Add(new Feature("CandlePattern", 0.0));
        }
Exemplo n.º 13
0
        /// <summary>
        /// Request candle data for a time range.
        /// 'diff_cache' means only request time ranges that appear missing in the local instrument cache db</summary>
        public void RequestTimeRange(DateTimeOffset t0, DateTimeOffset t1, bool diff_cache)
        {
            // The request message
            var msg = new OutMsg.RequestInstrumentHistory(SymbolCode, TimeFrame);

            // If the DB is currently empty, request the whole range
            if (!diff_cache || Count == 0)
            {
                msg.TimeRanges.Add(t0.Ticks);
                msg.TimeRanges.Add(t1.Ticks);
            }
            // Otherwise, request time ranges that are missing from the DB
            else
            {
                var time_ranges = new List <Range>();

                // One time frame unit
                var one = Misc.TimeFrameToTicks(1.0, TimeFrame);
                var ts  = "[" + nameof(Candle.Timestamp) + "]";

                // If the oldest candle in the DB is newer than 't0', request from t0 to Oldest
                if (Oldest.TimestampUTC > t0)
                {
                    Debug.Assert(!Equals(Oldest, Candle.Default));
                    time_ranges.Add(new Range(t0.Ticks, Oldest.Timestamp));
                }

                // Scan the DB for time ranges of missing data.
                var sql = Str.Build(                 // Returns pairs of timestamps that are the ranges of missing data.
                    $"select {ts} from {TimeFrame} where {ts} >= ? and {ts} <= ? and {ts}+? not in (select {ts} from {TimeFrame}) union all ",
                    $"select {ts} from {TimeFrame} where {ts} >= ? and {ts} <= ? and {ts}-? not in (select {ts} from {TimeFrame}) ",
                    $"order by {ts}");
                var args = new object[] { t0.Ticks, t1.Ticks, one, t0.Ticks, t1.Ticks, one, };

                // Note: ignore the first and last because they are the implicit ranges -inf to first, and last -> +inf
                foreach (var hole in m_db.EnumRows <long>(sql, 1, args).Skip(1).TakeAllBut(1).InPairs())
                {
                    time_ranges.Add(new Range(hole.Item1, hole.Item2));
                }

                // If the newest candle in the DB is older than 't1', request from Latest to t1
                if (Latest.TimestampUTC < t1)
                {
                    Debug.Assert(!Equals(Latest, Candle.Default));
                    time_ranges.Add(new Range(Latest.Timestamp, t1.Ticks));
                }

                // Exclude the known forex non trading hours
                foreach (var time_range in time_ranges)
                {
                    foreach (var hole in Model.Sessions.ClipToTradingHours(time_range))
                    {
                        Debug.Assert(hole.Size != 0);
                        msg.TimeRanges.Add(hole.Beg);
                        msg.TimeRanges.Add(hole.End);
                    }
                }
            }

            // Post the request
            Model.Post(msg);
        }
Exemplo n.º 14
0
 /// <summary>Remove a support and resistance level from the DB</summary>
 public static string RemoveSnRLevel()
 {
     return(Str.Build("delete from SnRLevels where [", nameof(SnRLevel.Id), "] = ?"));
 }