/// <summary> /// Retrieve candles from a file containing transactions /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="candleDurationInMinutes"></param> /// <param name="pair"></param> /// <param name="inputFile"></param> /// <returns></returns> public List<OHLC> GetCandlesFromCSVTransactions(DateTime from, DateTime? to, int candleDurationInMinutes, CurrencyPair pair, string inputFile = null) { if (string.IsNullOrEmpty(inputFile)) { inputFile = GetTransactionsStoreFileName(pair); } if (!File.Exists(inputFile)) { return new List<OHLC>(); } var fromTimeStamp = BitstampAPI.UnixTimeHelper.GetFromDateTime(from); var toTimeStamp = to != null ? BitstampAPI.UnixTimeHelper.GetFromDateTime(to.Value) : (uint?)null; long? nextStamp = null; int candleDurationInSeconds = candleDurationInMinutes * 60; List<decimal> pricesForCurrentCandle = new List<decimal>(); List<OHLC> candles = new List<OHLC>(); using (var sr = new StreamReader(inputFile)) { while (!sr.EndOfStream) { var line = sr.ReadLine(); var buf = line.Split(new[] { ',' }); long transTimeStamp = Convert.ToInt64(buf[0]); if (transTimeStamp < fromTimeStamp) { continue; } decimal price = Convert.ToDecimal(buf[1], CultureInfo.InvariantCulture); if (nextStamp == null) { nextStamp = transTimeStamp + candleDurationInSeconds; } if (transTimeStamp < nextStamp) { pricesForCurrentCandle.Add(price); } else//New candle { OHLC ohlc = new OHLC(); if (pricesForCurrentCandle.Count > 0) { ohlc = new OHLC { Open = pricesForCurrentCandle.First(), High = pricesForCurrentCandle.Max(), Low = pricesForCurrentCandle.Min(), Close = pricesForCurrentCandle.Last(), Date = BitstampAPI.UnixTimeHelper.ConvertToDateTime((uint)nextStamp) }; } else//No prices for this candle... use previous candle's close value { var prev = candles.Last(); ohlc = new OHLC { Open = prev.Close, High = prev.Close, Low = prev.Close, Close = prev.Close, Date = BitstampAPI.UnixTimeHelper.ConvertToDateTime((uint)nextStamp) }; } candles.Add(ohlc); nextStamp = nextStamp + candleDurationInSeconds; pricesForCurrentCandle.Clear(); if (toTimeStamp != null && nextStamp > toTimeStamp.Value) { break; } } } }//using return candles; }
public Advice GetAdvice(IList<OHLC> candles) { var shortMA = Analysis.MovingAverages.CalculateEMA(candles, _shortEMAPeriod); var longMA = Analysis.MovingAverages.CalculateEMA(candles, _longEMAPeriod); if (shortMA == null || longMA == null) { return Advice.None; } int firstIndex = _longEMAPeriod - 1; if (candles.Count < _longEMAPeriod + _signalPeriod - 1) { return Advice.None; } int i = candles.Count - 1; var emaDiff = new OHLC[i - firstIndex + 1]; for (int k = firstIndex; k <= i; k++) { emaDiff[k - firstIndex] = new OHLC { Close = (decimal)shortMA.Output[k - shortMA.Begin] - (decimal)longMA.Output[k - longMA.Begin] }; } var signal = Analysis.MovingAverages.CalculateEMA(emaDiff, _signalPeriod); if (signal == null) { return Advice.None; } var macdDiff = shortMA.Output[i - shortMA.Begin] - longMA.Output[i - longMA.Begin] - signal.Output[i - firstIndex - signal.Begin]; if (macdDiff > 0.025/* settings.thresholds.up*/) { // new trend detected if (this._trend.Direction != TrendDirection.Up) // reset the state for the new trend this._trend = new Trend { Duration = 0, Persisted = false, Direction = TrendDirection.Up, Adviced = false }; this._trend.Duration++; //log.debug('In uptrend since', this.trend.duration, 'candle(s)'); if (this._trend.Duration >= 1/*settings.thresholds.persistence*/) this._trend.Persisted = true; if (this._trend.Persisted && !this._trend.Adviced) { this._trend.Adviced = true; return Advice.Buy; } else return Advice.None; } else if (macdDiff < -0.025/* settings.thresholds.down*/) { // new trend detected if (this._trend.Direction != TrendDirection.Down) // reset the state for the new trend this._trend = new Trend { Duration = 0, Persisted = false, Direction = TrendDirection.Down, Adviced = false }; this._trend.Duration++; //log.debug('In downtrend since', this.trend.duration, 'candle(s)'); if (this._trend.Duration >= 1/*settings.thresholds.persistence*/) { this._trend.Persisted = true; } if (this._trend.Persisted && !this._trend.Adviced) { this._trend.Adviced = true; return Advice.Sell; } else return Advice.None; } else { return Advice.None; } }