public void ストアに登録済みのデータが存在する場合に終了時刻のみを指定してフェッチするとプロバイダーからデータを取得しない() { var symbol = new TradingSymbol("USD_JPY"); var range = ChartRange.Daily; var chart = new CandleChart(symbol, range); var from = new DateTime(2017, 12, 1, 0, 0, 0, DateTimeKind.Utc); var to = from.AddDays(10); var candles = Seeds.CreateRomdomCandles(from, to, range); // プロバイダーのセットアップ var provider = new MockCandleProvider(); provider.SetCandle(range, candles); // ストアは空 using (var store = new CandleChartStore(new DbContextOptionsBuilder() .UseInMemoryDatabase("CandleChartUpdaterTestDb4") .Options)) { // ストアに保存 var entry = store.FindOrCreateEntry(symbol, range); store.AddCandles(entry, from, to, candles.ToArray()); var chartUpdater = new CandleChartUpdater(chart, store, provider); chartUpdater.Update(from, 1); chartUpdater.Update(to); Assert.AreEqual(11, store.Candles.Count()); Assert.IsFalse(provider.ProvidedCandles.Any()); } }
public void キャンドルマネージャーに2件のキャンドルを設定して更新した場合にキャンドルが正しく更新される() { var sut = new CandleChartManager(current, (s, r) => mockProvider, store); var symbol1 = new TradingSymbol("USD_JPY"); var range1 = ChartRange.Daily; var chart1 = sut.GetChart(symbol1, range1); chart1.AddIndicator("SMA5", new SmaIndicator(5)); chart1.AddIndicator("SMA10", new SmaIndicator(10)); chart1.AddIndicator("SMA20", new SmaIndicator(20)); chart1.AddIndicator("SMA60", new SmaIndicator(60)); chart1.AddIndicator("SMA120", new SmaIndicator(120)); var symbol2 = new TradingSymbol("EUR_USD"); var range2 = ChartRange.Daily; var chart2 = sut.GetChart(symbol2, range2); chart2.AddIndicator("SMA5", new SmaIndicator(5)); chart2.AddIndicator("SMA10", new SmaIndicator(10)); chart2.AddIndicator("SMA20", new SmaIndicator(20)); chart2.AddIndicator("SMA60", new SmaIndicator(60)); chart2.AddIndicator("SMA120", new SmaIndicator(120)); var snapshotBeforeUpdate1 = chart1.Snapshot; var snapshotBeforeUpdate2 = chart2.Snapshot; sut.Update(to); var snapshotAfterUpdate1 = chart1.Snapshot; var snapshotAfterUpdate2 = chart2.Snapshot; Assert.IsTrue(snapshotBeforeUpdate1.Candles.Last().Time < snapshotAfterUpdate1.Candles.Last().Time); Assert.IsTrue(snapshotBeforeUpdate2.Candles.Last().Time < snapshotAfterUpdate2.Candles.Last().Time); }
public Candle[] GetCandles(TradingSymbol symbol, ChartRange range, DateTime to, int count) { var granularity = ConvertGranurality(range); var task = apiEndpoint.GetBidAskCandles(symbol.Symbol, granularity: granularity, count: count, end: to, includeFirst: true); return(task.Result.Select(oandaCandle => new Candle(oandaCandle.Time, oandaCandle.OpenAsk, oandaCandle.HighAsk, oandaCandle.LowAsk, oandaCandle.CloseAsk, oandaCandle.Volume)).ToArray()); }
public PriceSet GetPrices(TradingSymbol symbol, int year, int month) { int price_set_index = GetPriceSetIndex(year, month); string price_set_file_path = GetPriceSetFilePath(symbol, year, month); if (!data_loaded.ContainsKey(symbol)) { data_loaded[symbol] = new Dictionary <int, PriceSet>(); } if (data_loaded[symbol].ContainsKey(price_set_index)) { return(data_loaded[symbol][price_set_index]); } else { if (File.Exists(price_set_file_path)) { data_loaded[symbol][price_set_index] = PriceSet.Read(new BinaryReader(File.Open(price_set_file_path, FileMode.Open))); } else { data_loaded[symbol][price_set_index] = new PriceSet(symbol, new DateTimeUTC(year, month, 1), new DateTimeUTC(year, month + 1, 1)); } return(data_loaded[symbol][price_set_index]); } }
public static IReadOnlyList <PriceCandle> GetPriceCandles(TradingSymbol trading_symbol, TimeScale time_scale) { string data_path = Path.Combine(binary_data_root_path, trading_symbol.Broker, trading_symbol.Account, trading_symbol.Symbol, ToolsEnum.EnumToString(time_scale)); if (!Directory.Exists(data_path)) { throw new Exception("No data for trading symbol: " + trading_symbol); } string[] files = Directory.GetFiles(data_path); if (files.Length == 0) { throw new Exception("No data for trading symbol: " + trading_symbol); } using (BinaryReader reader = new BinaryReader(new FileStream(files[0], FileMode.Open))) { int count = reader.ReadInt32(); List <PriceCandle> candles = new List <PriceCandle>(count); for (int candle_index = 0; candle_index < count; candle_index++) { candles.Add(PriceCandle.Read(reader)); } return(candles); } }
public void SavePrices(TradingSymbol symbol, int year, int month) { int price_set_index = GetPriceSetIndex(year, month); string price_set_file_path = GetPriceSetFilePath(symbol, year, month); if (!data_loaded.ContainsKey(symbol)) { throw new Exception("Cant save this data"); } if (!data_loaded[symbol].ContainsKey(price_set_index)) { throw new Exception("Cant save unloaded data"); } if (!Directory.GetParent(price_set_file_path).Exists) { Directory.CreateDirectory(Directory.GetParent(price_set_file_path).ToString()); } using (BinaryWriter writer = new BinaryWriter(File.Open(price_set_file_path, FileMode.OpenOrCreate))) { data_loaded[symbol][price_set_index].Write(writer); } }
public static ICandleProvider GetInstance(TradingSymbol symbol) { if (factories.TryGetValue(symbol, out var factory)) { return(factory.Invoke()); } throw new ArgumentException($"provider for {symbol.Symbol} is not registered."); }
public Candle[] GetCandles(TradingSymbol symbol, ChartRange range, DateTime from, DateTime to) { if (candles.TryGetValue(range, out var value)) { var providingCandles = value.Where(c => c.Time >= from && c.Time <= to).ToArray(); ProvidedCandles.AddRange(providingCandles); return(providingCandles); } return(Array.Empty <Candle>()); }
public CandleChart(TradingSymbol symbol, ChartRange range, Candle[] candles) { foreach (var candle in candles) { latestCandle = candle; store.Enqueue(candle); } this.symbol = symbol; this.range = range; updateSnapshot(); }
public SymbolDataServiceEventArgs(string symbol) { if (!Market.Instance.Symbols.TryGetValue(symbol, out TradingSymbol found)) { throw new KeyNotFoundException($"The market does not contain the trading symbol {symbol}."); } else { Symbol = found; } }
public SymbolChangedEventArgs(string symbol, string oldSymbol) : base(symbol) { if (!Market.Instance.Symbols.TryGetValue(oldSymbol, out TradingSymbol found)) { throw new KeyNotFoundException($"The market does not contain the trading symbol {symbol}."); } else { OldSymbol = found; } }
public PriceSet GetPrices(TradingSymbol symbol, DateTimeUTC lower_inclusive, DateTimeUTC upper_exclusive) { List <PriceSet> month_price_set_list = new List <PriceSet>(); //Move through months DateTimeUTC initial_month = new DateTimeUTC(lower_inclusive.Year, lower_inclusive.Month, 1); int year = 0; int month = 0; PriceSet price_set = GetPrices(symbol, year, month); return(new PriceSet(month_price_set_list));// new PriceSet(List<PriceSet> month_price_set_list) }
public void 事前に登録したキャンドルプロバイダーをシンボルを指定して取得できる() { var symbol = new TradingSymbol("USD_JPY"); CandleProviderFactory.Register(symbol, () => new MockCandleProvider()); var sut = CandleProviderFactory.GetInstance(symbol); Assert.IsNotNull(sut); Assert.AreEqual("MockCandleProvider", sut.GetType().Name); }
public void チャートにキャンドルを読み込むとストアに登録される() { var date = DateTime.Now; var symbol = new TradingSymbol("USD_JPY"); var chart = new CandleChart(symbol, ChartRange.Hourly); chart.AddCandle(new Candle(date, 0, 48.70m, 47.79m, 48.16m, 0)); var snapshot = chart.Snapshot; Assert.AreEqual(date, snapshot.Candles.First().Time); }
public void OANDAサーバーよりキャンドルが取得できる() { var symbol = new TradingSymbol("USD_JPY"); var from = new DateTime(2017, 1, 1, 1, 0, 0, DateTimeKind.Utc); var to = new DateTime(2017, 1, 1, 10, 0, 0, DateTimeKind.Utc); var range = ChartRange.Hourly; var oandaApi = new OandaApi(_server.BaseUri, _server.DefaultAccessToken); var sut = new OandaCandleProvider(oandaApi); var candles = sut.GetCandles(symbol, range, from, to); Assert.AreEqual(10, candles.Length); }
public Candle[] GetCandles(TradingSymbol symbol, ChartRange range, DateTime to, int count) { if (candles.TryGetValue(range, out var value)) { var providingCandles = value.Where(c => c.Time <= to) .OrderByDescending(c => c.Time) .Take(count) .OrderBy(c => c.Time) .ToArray(); ProvidedCandles.AddRange(providingCandles); return(providingCandles); } return(Array.Empty <Candle>()); }
public ChartEntryEntity FindOrCreateEntry(TradingSymbol symbol, ChartRange range) { var entry = ChartEntries.Where(ce => ce.Symbol == symbol.Symbol && ce.Range == range).FirstOrDefault(); if (entry == null) { entry = new ChartEntryEntity() { Symbol = symbol.Symbol, Range = range, }; ChartEntries.AddAsync(entry); SaveChangesAsync(); } return(entry); }
public static List <PriceCandle> GetPriceCandles(TradingSymbol trading_symbol, TimeScale time_scale, DateTime start_inclusive, DateTime end_exclusive) { string data_path = Path.Combine(binary_data_root_path, trading_symbol.Broker, trading_symbol.Account, trading_symbol.Symbol, ToolsEnum.EnumToString(time_scale)); if (!Directory.Exists(data_path)) { throw new Exception("No data for trading symbol: " + trading_symbol); } string[] files = Directory.GetFiles(data_path); if (files.Length == 0) { throw new Exception("No data for trading symbol: " + trading_symbol); } return(ToolsIOSerialization.SerializeFromFile <List <PriceCandle> >(files[0])); }
public void データ登録済みのストアを指定してチャートを生成しインジケータを追加しインジケータが計算済みであること() { var date = DateTime.Now; var symbol = new TradingSymbol("USD_JPY"); var chart = new CandleChart(symbol, ChartRange.Hourly, Seeds.ATR14_CANDLES.Item1); chart.AddIndicator("ATR14", new AtrIndicator(14)); var snapshot = chart.Snapshot; CollectionAssert.AreEqual( Seeds.ATR14_CANDLES.Item2.Where(sv => sv != null).Select(sv => sv.Value).ToArray(), snapshot.Plot <SingleValue>("ATR14").Select(sv => Math.Round(sv.Value, 4)).ToArray() ); }
public void OANDAよりデータを取得してチャートが更新されることを確認する() { // 前提条件: // トレードをするクラスはチャートが常に勝手に最新に更新されていること // を想定して同期的にアクセス可能 // データを取得する単位はシンボル・チャートの足単位とする // (TODO: 最適化できれば複数のシンボル・チャート足を同時に取得したいけど、 // OANDA的に難しそうなのでとりあえず...分足から日足を生成するとか // -> ちなみに↑の最適化したい理由はリクエストが発生すると遅いから) // // 1. 更新スケジュールを作り、タイミングでトリガーを発生 // 2. トリガーでプロバイダよりデータを取得する // 3. プロバイダがデータを取得出来たらデータストアを更新 // 4. データストアはチャートマネージャに通知を送信 // 5. チャートマネージャは送られてきたデータによってチャートを更新する // 6. スレッドセーフになるように頑張る var symbol = new TradingSymbol("USD_JPY"); var range = ChartRange.Daily; var from = new DateTime(2017, 12, 1, 0, 0, 0, DateTimeKind.Utc); var to = new DateTime(2017, 12, 1, 0, 2, 0, DateTimeKind.Utc); var apiEndpoint = new OandaApi(_server.BaseUri, _server.DefaultAccessToken); var provider = new OandaCandleProvider(apiEndpoint) as ICandleProvider; var chartManager = new CandleChartManager(from, (s, r) => provider); var chart = chartManager.GetChart(symbol, range); // この時点で100件分のチャートが取得済み chart.AddIndicator("SMA10", new SmaIndicator(10)); var snapshot1 = chart.Snapshot; Assert.AreEqual(100, snapshot1.Candles.Length); Assert.AreEqual(100, snapshot1.Plot <SingleValue>("SMA10").Length); // これでチャートが更新される chartManager.Update(to); var snapshot2 = chart.Snapshot; Assert.AreEqual(100, snapshot2.Candles.Length); Assert.AreEqual(100, snapshot2.Plot <SingleValue>("SMA10").Length); // SNAPSHOT1とSNAPSHOT2のインスタンスが異なることを確認 Assert.AreNotSame(snapshot1, snapshot2); }
private PriceSet ImportSecondData(string file_path) { string symbol = Path.GetFileName(file_path).Substring(0, 6); TradingSymbol trading_symbol = new TradingSymbol("TradersWay", "MT4.VAR.DEMO", symbol, "The one we mine on the VM"); List <Price> price_list = new List <Price>(); string[,] table = ToolsIOCSV.ReadCSVFile(file_path); for (int index_0 = 0; index_0 < table.GetLength(0); index_0++) { //TODO duplicate date_times can exist both on the server and on the client DateTimeUTC date_time = ToolsTime.UnixTimeStampToDateTimeUTC(int.Parse(table[index_0, 0])); double bid = double.Parse(table[index_0, 2], CultureInfo.InvariantCulture); double ask = double.Parse(table[index_0, 3], CultureInfo.InvariantCulture); price_list.Add(new Price(date_time, bid, ask)); } return(new PriceSet(trading_symbol, price_list)); }
public static PriceSet GetPriceSet(TradingSymbol trading_symbol) { string data_path = Path.Combine(binary_data_root_path, trading_symbol.Broker, trading_symbol.Account, trading_symbol.Symbol); if (!Directory.Exists(data_path)) { throw new Exception("No data for trading symbol: " + trading_symbol); } string[] files = Directory.GetFiles(data_path); if (files.Length != 1) { throw new Exception("No unique data for trading symbol: " + trading_symbol); } using (BinaryReader reader = new BinaryReader(new FileStream(files[0], FileMode.Open))) { return(PriceSet.Read(reader)); } }
public static IReadOnlyList <Price> GetPriceList(TradingSymbol trading_symbol) { string file_path = Path.Combine(binary_data_root_path, trading_symbol.Broker, trading_symbol.Account, trading_symbol.Symbol, "Prices.bin"); if (!File.Exists(file_path)) { throw new Exception("No data for trading symbol: " + trading_symbol); } using (BinaryReader reader = new BinaryReader(new FileStream(file_path, FileMode.Open))) { int count = reader.ReadInt32(); List <Price> price_list = new List <Price>(count); for (int candle_index = 0; candle_index < count; candle_index++) { price_list.Add(Price.Read(reader)); } return(price_list); } }
public CandleChart GetChart(TradingSymbol symbol, ChartRange range) { var chartKey = Tuple.Create(symbol, range); if (charts.TryGetValue(chartKey, out var chartAndUpdater)) { return(chartAndUpdater.Item1); } var provider = candleProviderFactory(symbol, range); var chart = new CandleChart(symbol, range); var updater = new CandleChartUpdater(chart, store, provider); charts.Add(chartKey, Tuple.Create(chart, updater)); var now = currentTime; updater.Update(now, 100); return(chart); }
public static void ComposeBinary(TradingSymbol trading_symbol) { string source_data_path = Path.Combine(source_data_root_path, trading_symbol.Broker, trading_symbol.Account, trading_symbol.Symbol); string target_data_path = Path.Combine(binary_data_root_path, trading_symbol.Broker, trading_symbol.Account, trading_symbol.Symbol); if (!Directory.Exists(source_data_path)) { throw new Exception("No data for trading symbol: " + trading_symbol); } string[] files = Directory.GetFiles(source_data_path); if (files.Length == 0) { throw new Exception("No data for trading symbol: " + trading_symbol); } Array.Sort(files); List <Price> price_list = new List <Price>(); foreach (string file in files) { AddFileToPriceList(price_list, file); } PriceSet price_set = new PriceSet(ToolsPrice.DefaultSymbolGBPUSD, price_list); DateTimeUTC date_time_first = price_set.OpenDateTime; DateTimeUTC date_time_last = price_set.CloseDateTime; target_data_path = Path.Combine(target_data_path, date_time_first.ToString("yyyyMMddHHmmss") + "_" + date_time_last.ToString("yyyyMMddHHmmss") + ".blb"); string target_data_path_dir = Path.GetDirectoryName(target_data_path); if (!Directory.Exists(target_data_path_dir)) { Directory.CreateDirectory(target_data_path_dir); } using (BinaryWriter writer = new BinaryWriter(new FileStream(target_data_path, FileMode.Create))) { price_set.Write(writer); } }
public void チャートにATRを設定しキャンドルを読み込むと自動的にATRが計算される() { var symbol = new TradingSymbol("USD_JPY"); var chart = new CandleChart(symbol, ChartRange.Hourly); chart.AddIndicator("ATR14", new AtrIndicator(14)); chart.AddCandles(Seeds.ATR14_CANDLES.Item1); var snapshot = chart.Snapshot; var values = snapshot.Plot <SingleValue>("ATR14"); var i = 0; foreach (var val in Seeds.ATR14_CANDLES.Item2) { if (val != null) { var plot = values[i++]; Assert.AreEqual(val.Time, plot.Time); Assert.AreEqual(val.Value, Math.Round(plot.Value, 4)); } } }
public void チャートに保持するインジケータの計算結果が最大100件までとなる() { var date = DateTime.Now; var symbol = new TradingSymbol("USD_JPY"); var chart = new CandleChart(symbol, ChartRange.Hourly); chart.AddIndicator("SMA5", new SmaIndicator(5)); Enumerable.Range(1, 100).ToList() .ForEach(i => { chart.AddCandle(new Candle(date.AddDays(i), i, i, i, i, i)); var snapshot1 = chart.Snapshot; Assert.AreEqual(i, snapshot1.Plot <SingleValue>("SMA5").Length); }); chart.AddCandle(new Candle(date.AddDays(101), 101, 101, 101, 101, 101)); var snapshot2 = chart.Snapshot; Assert.AreEqual(100, snapshot2.Candles.Length); Assert.AreEqual(100, snapshot2.Plot <SingleValue>("SMA5").Length); }
public void ストアにデータが存在しない場合に取得数を指定してフェッチするとプロバイダーからデータを取得する() { var symbol = new TradingSymbol("USD_JPY"); var range = ChartRange.Daily; var chart = new CandleChart(symbol, range); var to = new DateTime(2017, 12, 10, 0, 0, 0, DateTimeKind.Utc); var candles = Seeds.CreateRomdomCandles(to.AddDays(-20), to, range); // プロバイダーのセットアップ var provider = new MockCandleProvider(); provider.SetCandle(range, candles); // ストアは空 using (var store = new CandleChartStore(new DbContextOptionsBuilder() .UseInMemoryDatabase("CandleChartUpdaterTestDb1") .Options)) { var chartUpdater = new CandleChartUpdater(chart, store, provider); chartUpdater.Update(to, 10); Assert.AreEqual(10, store.Candles.Count()); } }
private string GetPriceSetFilePath(TradingSymbol symbol, int year, int month) { return(Path.Combine(database_path, symbol.ToString(), year + month.ToString("00") + ".dat")); }
public SymbolChangedEventArgs(TradingSymbol symbol, TradingSymbol oldSymbol) : base(symbol) { OldSymbol = OldSymbol; }