using System; using System.Net.Sockets; using sharp.trading; namespace sharp.tradebot { public class SimpleBot : TradingBot { public SimpleBotSetup Setup { get; private set; } = new SimpleBotSetup(); TradeStep[] TradeSteps; Market market; public SimpleBot() { } public override void Prepare() { base.Prepare(); Setup = loadJSON("setup.json"); TradeSteps = loadJSON("tradesteps.json"); checkTradeSteps(); } void checkTradeSteps(){ if (TradeSteps.Length == 0){ TradeSteps = new TradeStep[Setup.HalfSteps*2]; for (int n = 0; n < TradeSteps.Length; n++){ TradeSteps[n] = new TradeStep(); TradeSteps[n].price_buy = Setup.CenterPrice * ((1.0 - Setup.HalfSpread) + ((double)n * Setup.HalfSpread / (Setup.HalfSteps))); TradeSteps[n].price_sell = TradeSteps[n].price_buy * (1.0 + Setup.Offset); TradeSteps[n].current_base_volume = StepBaseVolume(); TradeSteps[n].current_market_volume = StepMarketVolume(); } } } double StepBaseVolume() { return Setup.ActiveBaseBalance / (2 * Setup.HalfSteps); } double StepMarketVolume() { return Setup.ActiveMarketBalance / (2 * Setup.HalfSteps); } public bool IsRunnable(){ if (Setup.marketSymbol == null || Setup.marketSymbol.Equals("")) return false; if (Setup.baseSymbol == null || Setup.baseSymbol.Equals("")) return false; return true; } public void Trade() { if (IsRunnable()){ market = TradingEnvironment.DefaultConnection.openMarket(Setup.marketSymbol, Setup.baseSymbol); } if (Setup.Enabled && IsRunnable()){ Log("SimpleBot is trading"); checkOrders(); } else if (IsRunnable()){ Console.WriteLine("SimpleBot instance is not enabled: {0}",this.UID); Market market = TradingEnvironment.DefaultConnection.openMarket(Setup.marketSymbol, Setup.baseSymbol); OrderBook orderbook = market.getOrderBook(); Console.WriteLine("Current Minimum Tradesize is {0:#0.00000000} {1}",market.MinimumTradeVolume,market.TradedSymbol); Console.WriteLine("Current Best Bid: {0:#0.00000000} {1} Current best Ask: {2:#0.00000000} {3} , so at the Moment I would...",orderbook.CurrentBid,Setup.baseSymbol,orderbook.CurrentAsk,Setup.baseSymbol); foreach (TradeStep step in TradeSteps) { if (step.price_buy < orderbook.CurrentAsk) { Console.WriteLine("Buy {0,8:##0.0000} {1} @ {2,11:##0.000000} {3} := {4,11:##0.000000} {5}", step.volume_to_buy(step.current_base_volume), Setup.marketSymbol, step.price_buy, Setup.baseSymbol, step.volume_to_buy(step.current_base_volume) * step.price_buy, Setup.baseSymbol); } } foreach (TradeStep step in TradeSteps) { if (step.price_sell > orderbook.CurrentBid) { Console.WriteLine("Sell {0,8:##0.0000} {1} @ {2,11:##0.000000} {3} := {4,11:##0.000000} {5}", step.volume_to_sell(step.current_market_volume * Setup.CenterPrice), Setup.marketSymbol, step.price_sell, Setup.baseSymbol, step.volume_to_sell(step.current_market_volume * Setup.CenterPrice) * step.price_sell, Setup.baseSymbol); } } } else { Console.WriteLine("SimpleBot instance is not enabled and not ready to run: {0}",this.UID); } } void Sell(TradeStep step){ if (!Setup.CancelAllOrders) { double volsell = step.volume_to_sell(step.current_market_volume * Setup.CenterPrice); Order sell = createLimitOrder(OrderType.SELL, Setup.marketSymbol, Setup.baseSymbol, volsell, step.price_sell); step.current_sell_order_id = sell.OrderID; } } void Buy(TradeStep step) { if (!Setup.CancelAllOrders) { double volbuy = step.volume_to_buy(step.current_base_volume); Order buyorder = createLimitOrder(OrderType.BUY, Setup.marketSymbol, Setup.baseSymbol, volbuy, step.price_buy); step.current_buy_order_id = buyorder.OrderID; } } void checkOrders() { foreach (TradeStep step in TradeSteps) { switch (step.getState()) { case StepState.BUYING: { Order order = getOrder(step.current_buy_order_id); if (!order.IsOpen) { double mRes = order.FilledVolume * (Setup.Offset - Setup.Fee) * Setup.Reserve; Setup.ActiveBaseBalance -= order.PayedPrice; Setup.ActiveBaseBalance -= order.PayedFees; Setup.ActiveMarketBalance += order.FilledVolume - mRes; Setup.ReservedMarketBalance += mRes; step.current_buy_order_id = null; Log("BUYED: {0} {1} @ {2} {3} Cost: {4} {5}", order.FilledVolume, Setup.marketSymbol, order.LimitPrice, Setup.baseSymbol, order.PayedPrice + order.PayedFees, Setup.baseSymbol); Sell(step); } else if (Setup.CancelAllOrders){ TradingEnvironment.DefaultConnection.cancelOrder(order); } } break; case StepState.SELLING: { Order order = getOrder(step.current_sell_order_id); if (!order.IsOpen) { double bRes = order.PayedPrice * (Setup.Offset - Setup.Fee) * Setup.Reserve; Setup.ActiveBaseBalance += order.PayedPrice - bRes; Setup.ActiveBaseBalance -= order.PayedFees; Setup.ReservedBaseBalance += bRes; Setup.ActiveMarketBalance -= order.FilledVolume; step.current_sell_order_id = null; Log("SOLD: {0} {1} @ {2} {3} Cost: {4} {5}", order.FilledVolume, Setup.marketSymbol, order.LimitPrice, Setup.baseSymbol, order.PayedPrice + order.PayedFees, Setup.baseSymbol); Buy(step); } else if (Setup.CancelAllOrders){ TradingEnvironment.DefaultConnection.cancelOrder(order); } } break; case StepState.NONE: if (step.price_buy < market.getOrderBook().CurrentAsk) { Buy(step); } else if (step.price_sell > market.getOrderBook().CurrentBid) { Sell(step); } break; } } } public override void Save() { if (Setup.Enabled) { saveJSON(Setup,"setup.json"); saveJSON(TradeSteps, "tradesteps.json"); } base.Save(); } public class SimpleBotSetup { public bool Enabled = false; public bool CancelAllOrders = false; public string marketSymbol = ""; public string baseSymbol = ""; public double CenterPrice; public double HalfSpread = 0.20; public double Offset = 0.0125; public int HalfSteps = 40; public double ActiveMarketBalance = 0; public double ReservedMarketBalance = 0; public double ActiveBaseBalance = 0; public double ReservedBaseBalance = 0; public double Reserve = 0.5; public double Fee = 0.0025; } public enum StepState { NONE, SELLING, BUYING } public class TradeStep { public double price_buy; public double price_sell; public double current_base_volume; public double current_market_volume; public string current_buy_order_id; public string current_sell_order_id; public double volume_to_buy(double base_volume){ return Math.Round(base_volume / price_buy, 4); } public double volume_to_sell(double base_volume) { return Math.Round(base_volume / price_sell, 4); } public StepState getState(){ if (current_buy_order_id != null){ return StepState.BUYING; } if (current_sell_order_id != null){ return StepState.SELLING; } return StepState.NONE; } public override string ToString() { return string.Format("[TradeStep buy={0,11:##.000000} sell={0,11:##.000000}]",price_buy,price_sell); } } } }