public void Start() { if (!isStarted) { EofR1ExeThread = new Thread(() => WatchMarkets()); EofR1ExeThread.IsBackground = true; EofR1ExeThread.Name = "EMAofRSI1-ExecutionLoop-Thread"; EofR1ExeThread.Start(); isStarted = true; } StopLossController.StartWatching(); }
private void LoadHoldings() { //Load held assets, stoploss amts, from SQLite for each period: AddHoldingsTable("period5m"); AddHoldingsTable("period20m"); AddHoldingsTable("period1h"); AddHoldingsTable("period4h"); AddHoldingsTable("period12h"); AddHoldingsTable("OpenOrders"); //REGISTER EXISTING STOPLOSS RATES FOR EACH HOLDING foreach (DataTable dt in Holdings.Tables) { if (dt.TableName == "OpenOrders") { continue; } foreach (DataRow row in dt.Rows) { var stopLoss = new StopLoss((string)row["MarketDelta"], Convert.ToDecimal(row["StopLossRate"]), Convert.ToDecimal(row["Qty"]), (a, b, c) => ReCalcStoploss(a, b, c), (a, b) => StopLossExecutedCallback(a, b), dt.TableName, OPTIONS.VITRUAL_MODE); if (OPTIONS.SAFE_MODE) { if (Convert.ToDecimal(row["BoughtRate"]) > stopLoss.StopRate) { stopLoss.StopRate = Convert.ToDecimal(row["BoughtRate"]) * 0.68M; } } //Trace.WriteLine(string.Format("{0}_{1} ... {2} ... {3} ... {4}", stopLoss.CandlePeriod, stopLoss.MarketDelta, stopLoss.Quantity, stopLoss.StopRate, stopLoss.virtualSL)); StopLossController.RegisterStoploss(stopLoss, string.Format("{0}_{1}", stopLoss.CandlePeriod, stopLoss.MarketDelta)); } } //Load Total From SQLite data: LoadTradingTotal(); }
public void ReCalcStoploss(string market, decimal oldRate, string period) { //RECALC NEW STOPLOSSRATE, THEN RAISE REGISTERED RATE IF HIGHER NOW: decimal boughtRate = 0; decimal ATR = 0; try { ATR = CalcStoplossMargin(market, period); boughtRate = Convert.ToDecimal(Holdings.Tables[period].Select(string.Format("MarketDelta = '{0}'", market))[0]["BoughtRate"]); } catch (Exception e) { Trace.WriteLine(" ****ERR RECALC-STOPLOSS>>> " + market + " | " + period + "... BOUGHT: " + boughtRate + " ... RATE: " + ATR); return; } //TIERED TRAILING STOPLOSS: //Teir 2 (calculate): var stoplossRate = BtrexData.Markets[market].TradeHistory.RecentFills.Last().Rate - (ATR * OPTIONS.ATRmultipleT2); var tier = "**"; //Use Teir 1, if T2 is below profit line: if (stoplossRate < boughtRate * 1.0025M) { stoplossRate = BtrexData.Markets[market].TradeHistory.RecentFills.Last().Rate - (ATR * OPTIONS.ATRmultipleT1); if (OPTIONS.SAFE_MODE) { stoplossRate = 0.0M; } tier = "*"; } //Use Teir 3, if current rate is above 8% profit: if (BtrexData.Markets[market].TradeHistory.RecentFills.Last().Rate > boughtRate * 1.1M) { stoplossRate = BtrexData.Markets[market].TradeHistory.RecentFills.Last().Rate - (ATR * OPTIONS.ATRmultipleT3); tier = "***"; } if (Math.Round(stoplossRate, 8) > Math.Round(oldRate, 8)) { var SLmovedTime = DateTime.UtcNow; //RAISE SL: StopLossController.RaiseStoploss(string.Format("{0}_{1}", period, market), stoplossRate); //CHANGE IN HOLDINGS: var row = Holdings.Tables[period].Select(string.Format("MarketDelta = '{0}'", market)); row[0]["StopLossRate"] = stoplossRate; //CREATE & ENQUEUE SQLDataWrite: var update = new SaveDataUpdate(period, market, "SL_MOVE", SLmovedTime, 0, 0, stoplossRate); SQLDataUpdateWrites.Enqueue(update); //OUTPUT STOPLOSS MOVED: if (OPTIONS.LogStoplossRaised) { Trace.WriteLine(string.Format("{0}{1}_{2} STOPLOSS-RAISED from {3:0.00000000} to {4:0.00000000}{5}", "[" + SLmovedTime + "] ::: ", period.Remove(0, 6), market, oldRate, stoplossRate, tier )); } } }
public void OrderExecutedCallback(OpenOrder OrderData) { //Find + REMOVE FROM OpenOrders TABLE, var OpenOrderRows = Holdings.Tables["OpenOrders"].Select(string.Format("UniqueID = '{0}_{1}'", OrderData.CandlePeriod, OrderData.Exchange)); foreach (var row in OpenOrderRows) { Holdings.Tables["OpenOrders"].Rows.Remove(row); } OrderData.PricePerUnit = Math.Round((OrderData.TotalReserved / OrderData.TotalQuantity), 8); if (OrderData.Type == "LIMIT_BUY") { //Calculate stoploss, within acceptable range per PeriodLength: decimal stoplossRate = OrderData.PricePerUnit - (CalcStoplossMargin(OrderData.Exchange, OrderData.CandlePeriod) * OPTIONS.ATRmultipleT1); switch (OrderData.CandlePeriod) { case "period5m": if (stoplossRate / OrderData.PricePerUnit < 0.98M) { stoplossRate = OrderData.PricePerUnit * 0.98M; } break; case "period20m": if (stoplossRate / OrderData.PricePerUnit < 0.95M) { stoplossRate = OrderData.PricePerUnit * 0.95M; } break; case "period1h": if (stoplossRate / OrderData.PricePerUnit < 0.93M) { stoplossRate = OrderData.PricePerUnit * 0.93M; } break; case "period4h": if (stoplossRate / OrderData.PricePerUnit < 0.90M) { stoplossRate = OrderData.PricePerUnit * 0.90M; } break; case "period12h": if (stoplossRate / OrderData.PricePerUnit < 0.88M) { stoplossRate = OrderData.PricePerUnit * 0.88M; } break; } //If 'SAFEMMODE' then Stoploss will be set to sell at minimum satoshis until profitable: if (OPTIONS.SAFE_MODE) { stoplossRate = 0.00105M / OrderData.TotalQuantity; } //Register new StopLoss in controller: StopLossController.RegisterStoploss(new StopLoss(OrderData.Exchange, stoplossRate, OrderData.TotalQuantity, (a, b, c) => ReCalcStoploss(a, b, c), (a, b) => StopLossExecutedCallback(a, b), OrderData.CandlePeriod, OPTIONS.VITRUAL_MODE), string.Format("{0}_{1}", OrderData.CandlePeriod, OrderData.Exchange)); //Enter into Holdings Table: var newHoldingsRow = Holdings.Tables[OrderData.CandlePeriod].NewRow(); newHoldingsRow["MarketDelta"] = OrderData.Exchange; newHoldingsRow["DateTimeBUY"] = OrderData.Closed; newHoldingsRow["Qty"] = OrderData.TotalQuantity; newHoldingsRow["BoughtRate"] = OrderData.PricePerUnit; newHoldingsRow["DateTimeSELL"] = "OWNED"; newHoldingsRow["SoldRate"] = "OWNED"; newHoldingsRow["StopLossRate"] = stoplossRate; newHoldingsRow["SL_Executed"] = 0; Holdings.Tables[OrderData.CandlePeriod].Rows.Add(newHoldingsRow); //Create + Enqueue SaveDataUpdate + OrderUpdate var update = new SaveDataUpdate(OrderData.CandlePeriod, OrderData.Exchange, "BUY", (DateTime)OrderData.Closed, OrderData.TotalQuantity, OrderData.PricePerUnit, stoplossRate); SQLDataUpdateWrites.Enqueue(update); SQLOrderUpdateWrites.Enqueue(OrderData); //OUTPUT BUY Trace.WriteLine(string.Format("{0}{1} Bought {2} at {3:0.00000000}, SL_Rate: {4:0.00000000}", OPTIONS.VITRUAL_MODE ? "[VIRTUAL|" + OrderData.Closed + "] ::: " : "[" + OrderData.Closed + "] ::: ", OrderData.CandlePeriod.Remove(0, 6), OrderData.Exchange.Split('-')[1], OrderData.PricePerUnit, stoplossRate)); } else if (OrderData.Type == "LIMIT_SELL") { StopLossController.CancelStoploss(string.Format("{0}_{1}", OrderData.CandlePeriod, OrderData.Exchange)); //Find row in Holdings: var holdingRows = Holdings.Tables[OrderData.CandlePeriod].Select(string.Format("MarketDelta = '{0}'", OrderData.Exchange)); //Calc profit with BoughtRate and include fees: var profit = ((OrderData.PricePerUnit / Convert.ToDecimal(holdingRows[0]["BoughtRate"])) - 1M); //Calc compound multiple var compoundMultiple = ((Convert.ToDecimal(holdingRows[0]["BoughtRate"]) * Convert.ToDecimal(holdingRows[0]["Qty"])) / OPTIONS.BTCwagerAmt); //Calc TradingTotal and NetWorth TradingTotal += (profit * compoundMultiple); var netWorth = GetNetPercentage(); var timeHeld = OrderData.Closed - Convert.ToDateTime(holdingRows[0]["DateTimeBUY"]); //Remove from Holdings: foreach (var row in holdingRows) { Holdings.Tables[OrderData.CandlePeriod].Rows.Remove(row); } //Create and add the SQL SaveDataUpdate + OrderUpdate var update = new SaveDataUpdate(OrderData.CandlePeriod, OrderData.Exchange, "SELL", (DateTime)OrderData.Closed, OrderData.TotalQuantity, OrderData.PricePerUnit, null, false, TradingTotal); SQLDataUpdateWrites.Enqueue(update); SQLOrderUpdateWrites.Enqueue(OrderData); //OUTPUT SELL-ON-SIGNAL Trace.Write(string.Format("{0}{1} Sold {2} at {3}\r\n =TradeProfit: ", OPTIONS.VITRUAL_MODE ? "[VIRTUAL|" + OrderData.Closed + "] ::: " : "[" + OrderData.Closed + "] ::: ", OrderData.CandlePeriod.Remove(0, 6), OrderData.Exchange.Split('-')[1], OrderData.PricePerUnit)); //OUTPUT PROFIT ON TRADE: if (profit < 0) { Console.ForegroundColor = ConsoleColor.Red; } else if (profit > 0) { Console.ForegroundColor = ConsoleColor.Green; } Trace.Write(string.Format("{0:+0.###%;-0.###%;0}", profit)); //OUTPUT TIME HELD Console.ForegroundColor = ConsoleColor.DarkCyan; Trace.Write(string.Format(".....=Time-Held: {0:hh\\:mm\\:ss}.....", timeHeld)); //OUTPUT GROSS TOTAL PROFIT PERCENTAGE: if (TradingTotal < 0) { Console.ForegroundColor = ConsoleColor.Red; } else if (TradingTotal > 0) { Console.ForegroundColor = ConsoleColor.Green; } else { Console.ForegroundColor = ConsoleColor.DarkCyan; } Trace.Write(string.Format("=GrossProfit: {0:+0.###%;-0.###%;0}", TradingTotal / OPTIONS.MAXTOTALENTRANCES)); Console.ForegroundColor = ConsoleColor.DarkCyan; Trace.Write("....."); //OUTPUT CURRENT NET WORTH PERCENTAGE INCLUDING HOLDINGS: if (netWorth > 0) { Console.ForegroundColor = ConsoleColor.DarkGreen; } else if (netWorth < 0) { Console.ForegroundColor = ConsoleColor.DarkRed; } else { Console.ForegroundColor = ConsoleColor.DarkCyan; } Trace.WriteLine(string.Format("=CurrentNetWorth: {0:+0.###%;-0.###%;0}", netWorth)); Console.ForegroundColor = ConsoleColor.DarkCyan; } }
private void WatchMarkets() { using (var cmd = new SQLiteCommand(conn)) { while (true) //!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Backspace)) { //WRITE/SAVE SQL DATA CHANGES: SaveSQLOrderData(cmd); SaveSQLData(cmd); //BEGIN CANDLES ASSESSMENTS: foreach (Market m in BtrexData.Markets.Values) { //CHECK FOR NEW CANDLES: if (m.TradeHistory.LastStoredCandle > StratData.Candles5m[m.MarketDelta].Last().DateTime) { //Get new 5m candles: var Importer = new TradyCandleImporter(); var newCandles = Importer.ImportAsync(m.MarketDelta, StratData.Candles5m[m.MarketDelta].Last().DateTime.AddMinutes(5)).Result; StratData.Candles5m[m.MarketDelta].AddRange(newCandles); CheckStrategy(StratData.Candles5m[m.MarketDelta].Skip(Math.Max(0, StratData.Candles5m[m.MarketDelta].Count - 42)).ToList(), m.MarketDelta, "period5m"); //Build new 20m candles + Check strategy for buy/sell signals: var CandleCurrentTime = m.TradeHistory.LastStoredCandle.AddMinutes(5); if (CandleCurrentTime > StratData.Candles20m[m.MarketDelta].Last().DateTime.AddMinutes(40)) { if (StratData.BuildNew20mCndls(m.MarketDelta)) { CheckStrategy(StratData.Candles20m[m.MarketDelta].Skip(Math.Max(0, StratData.Candles20m[m.MarketDelta].Count - 42)).ToList(), m.MarketDelta, "period20m"); } //Build new 1h candles + Check strategy for buy/sell signals: if (CandleCurrentTime > StratData.Candles1h[m.MarketDelta].Last().DateTime.AddHours(2)) { if (StratData.BuildNew1hCndls(m.MarketDelta)) { CheckStrategy(StratData.Candles1h[m.MarketDelta].Skip(Math.Max(0, StratData.Candles1h[m.MarketDelta].Count - 42)).ToList(), m.MarketDelta, "period1h"); } //Build new 4h candles + Check strategy for buy/sell signals: if (CandleCurrentTime > StratData.Candles4h[m.MarketDelta].Last().DateTime.AddHours(8) && StratData.BuildNew4hCndls(m.MarketDelta)) { CheckStrategy(StratData.Candles4h[m.MarketDelta].Skip(Math.Max(0, StratData.Candles4h[m.MarketDelta].Count - 42)).ToList(), m.MarketDelta, "period4h"); } //Build new 12h candles + Check strategy for buy/sell signals: if (CandleCurrentTime > StratData.Candles12h[m.MarketDelta].Last().DateTime.AddHours(24) && StratData.BuildNew12hCndls(m.MarketDelta)) { CheckStrategy(StratData.Candles12h[m.MarketDelta].Skip(Math.Max(0, StratData.Candles12h[m.MarketDelta].Count - 42)).ToList(), m.MarketDelta, "period12h"); } } } } } //EXECUTE ALL List<NewOrders>: if (NewOrders.Count > 0) { //PendingOrders.AddRange(NewOrders); var ords = new List <NewOrder>(NewOrders); NewOrders = new List <NewOrder>(); //This is not awaited because NewOrder objects reference their own callback BtrexREST.TradeController.ExecuteNewOrderList(ords, OPTIONS.VITRUAL_MODE); } Thread.Sleep(TimeSpan.FromSeconds(3)); } //CONTROL-LOOP ENDED: StopLossController.Stop(); } conn.Close(); isStarted = false; Trace.WriteLine("\r\n\r\n @@@ EMAofRSI1 Strategy STOPPED @@@\r\n\r\n"); }