public void ComputeNewOrders(ref TradingContext tContext) { foreach (IContextualStrategy objAction in this.Instances) { objAction.ComputeNewOrders(ref tContext); } }
public Wallet ComputeNewOrders(Wallet currentOrders, MarketInfo objMarket, ExchangeInfo objExchange, TradingHistory history) { //the newOrders Wallet variable will contain all ask/bid/cancel orders to issue var newOrders = new Wallet(); //start with reserved resource //Dim askReserve As Decimal = Math.Max(Me._AskReserveAmount, currentOrders.btcs * (Me._AskReserveRate / 100)) //Dim bidReserve As Decimal = Math.Max(Me._BidReserveValue, currentOrders.usds * (Me._BidReserveRate / 100)) decimal avBtcsForTrading = currentOrders.PrimaryBalance; //- askReserve decimal avUsdsForTrading = currentOrders.SecondaryBalance; //- bidReserve //Then We simplify the current orders by merging orders of the same price, issueing corresponding cancel/new orders newOrders.ConsolidateOrders(ref currentOrders, true); //Feed the new orders wallet with available resources, Reserve resources for current open orders newOrders.PrimaryBalance = Math.Max(avBtcsForTrading - currentOrders.GetTotalAsksPrimary(), 0); newOrders.SecondaryBalance = Math.Max(avUsdsForTrading - currentOrders.GetTotalBidsSecondary(), 0); var tContext = new TradingContext(currentOrders, newOrders, objMarket, objExchange, history.GetLastTrend(), this); this.ComputeNewOrders(ref tContext); tContext.NewOrders.FitOrders(objExchange); //we update the trading history with last data history.Update(currentOrders, objMarket, tContext.NewOrders); return(tContext.NewOrders); }
public void ComputeNewOrders(ref TradingContext tContext) { if (this.Condition.Evaluate(tContext, tContext)) { this.Strategy.ComputeNewOrders(ref tContext); if (!string.IsNullOrEmpty(this.NewStatus)) { tContext.CurrentOrders.Status = this.NewStatus; tContext.NewOrders.Status = this.NewStatus; } } }
public override void ComputeNewOrders(ref TradingContext tContext) { var newOrder = ReflectionHelper.CloneObject <Order>(this.StaticOrder); if (this.DynamicAmount) { newOrder.Amount = this.DynamicAmountExpression.Evaluate(tContext, tContext); } if (this.DynamicPrice) { newOrder.Price = this.DynamicPriceExpression.Evaluate(tContext, tContext); } if (this.DynamicType) { newOrder.Type = this.DynamicTypeExpression.Evaluate(tContext, tContext); } if (this.DynamicId) { newOrder.Oid = this.DynamicIdExpression.Evaluate(tContext, tContext); } tContext.NewOrders.Orders.Add(newOrder); }
public Wallet ComputeNewOrders(Wallet currentOrders, MarketInfo objMarket, ExchangeInfo objExchange, TradingHistory history) { var newOrders = new Wallet(); var askReserve = Math.Max(this.AskReserveAmount, currentOrders.PrimaryBalance * AskReserveRate / 100m); var bidReserve = Math.Max(this.BidReserveValue, currentOrders.SecondaryBalance * BidReserveRate / 100m); decimal avBtcsForTrading = currentOrders.PrimaryBalance - askReserve; decimal avUsdsForTrading = currentOrders.SecondaryBalance - bidReserve; //todo: should we update the original wallet? newOrders.ConsolidateOrders(ref currentOrders, true); newOrders.PrimaryBalance = Math.Max(avBtcsForTrading - currentOrders.GetTotalAsksPrimary(), decimal.Zero); newOrders.SecondaryBalance = Math.Max(decimal.Subtract(avUsdsForTrading, currentOrders.GetTotalBidsSecondary()), decimal.Zero); var tContext = new TradingContext(currentOrders, newOrders, objMarket, objExchange, history.GetLastTrend(), this); this.ComputeNewOrders(ref tContext); if (this.NoAsks) { tContext.NewOrders.ClearAsks(); if (this.ClearAsks) { tContext.NewOrders.CancelExistingOrders(tContext.CurrentOrders.OrderedAsks.ToArray()); } } if (this.NoBids) { tContext.NewOrders.ClearBids(); if (this.ClearBids) { tContext.NewOrders.CancelExistingOrders(tContext.CurrentOrders.OrderedBids.ToArray()); } } tContext.NewOrders.FitOrders(objExchange); history.Update(currentOrders, objMarket, tContext.NewOrders); return(tContext.NewOrders); }
public BandTradingContext(TradingContext objBaseContext) : base(objBaseContext.CurrentOrders, objBaseContext.NewOrders, objBaseContext.Market, objBaseContext.Exchange, objBaseContext.LastTrend, objBaseContext.BaseStrategy) { }
public abstract void ComputeNewOrders(ref TradingContext tContext);
public override void ComputeNewOrders(ref TradingContext tContext) { this._strategies.ComputeNewOrders(ref tContext); }
public override void ComputeNewOrders(ref TradingContext tContext) { tContext = new BandTradingContext(tContext); //this is because some user defined expressions are computed in loops: // we don't want the algorithm to get stuck in an infinite loop int safetyCounter = 0; // First we deal with asks if (!this.NoAsks) { if (tContext.CurrentOrders.OrderedAsks.Count == 0) { if (this.AccountForTrend || tContext.LastTrend != TradingTrend.Ask) { // There is no asks order yet/anymore, define a single new ask order //Compute price from current ticker and strategy var newHighAskPrice = tContext.Market.Ticker.Last * (1m + DefaultBandWidthRate / 100m); var newOrder = new Order() { OrderType = OrderType.Sell, Price = newHighAskPrice, //compute amount from available balance and strategy Amount = (tContext.NewOrders.PrimaryBalance * tContext.Market.Ticker.Last / newHighAskPrice) * DefaultMaxOrderValueRate / 100m }; tContext.NewOrders.Orders.Add(newOrder); } } // else: There are asks orders already, we'll base new orders according to the existing else if (tContext.CurrentOrders.HighestAsk.Price < tContext.Market.Ticker.Last * (1m + MinBandWidthRate / 100m) || tContext.CurrentOrders.HighestAsk.Price > tContext.Market.Ticker.Last * (1m + MaxBandWidthRate / 100m)) { // The band is not within defined bound: clear existing orders in order to define a new band tContext.NewOrders.CancelExistingOrders(tContext.CurrentOrders.OrderedAsks.ToArray()); } else if (tContext.NewOrders.PrimaryBalance * tContext.Market.Ticker.Last < tContext.CurrentOrders.HighestAsk.Value * VolumeResetLimitFactor) { //the amount of available resource is too low for the existing band: clear orders to define a new band tContext.NewOrders.CancelExistingOrders(tContext.CurrentOrders.OrderedAsks.ToArray()); } else { //we start with new low orders: have we got new orders to issue ? if (!AccountForTrend || tContext.LastTrend != TradingTrend.Ask || tContext.CurrentOrders.OrderedAsks.Count < 2) { decimal newPrice, limitPrice; SimpleExpression <Decimal> pricingExpression; var sign = (int)TradingBandDirection; if (TradingBandDirection == TradingBandDirection.Outwards) { pricingExpression = NextAskOrderPriceExpression; newPrice = tContext.LowestAskLimitPrice; limitPrice = tContext.LowestAsk.Price; } else { pricingExpression = MinAskOrderPriceExpression; newPrice = pricingExpression.Evaluate(tContext, tContext); limitPrice = tContext.LowestAskLimitPrice; } //How close are we to the lowest limit ask price? safetyCounter = 0; while (newPrice > 0 && sign * newPrice < sign * limitPrice && safetyCounter < 500) { safetyCounter += 1; // We are within the authorized inner band , place new order var newOrder = new Order { OrderType = OrderType.Sell, Price = newPrice }; //set price to context to compute the new order amount tContext.Price = newPrice; newOrder.Amount = AskOrderAmountExpression.Evaluate(tContext, tContext); if (TradingBandDirection == TradingBandDirection.Inwards) { tContext.NewOrders.Orders.Add(newOrder); } newPrice = pricingExpression.Evaluate(tContext, tContext); if (TradingBandDirection == TradingBandDirection.Outwards && sign * newPrice < sign * limitPrice) { tContext.NewOrders.Orders.Add(newOrder); } } } //then we check existing orders for cancelling or increasing for (var i = 0; i <= tContext.CurrentOrders.OrderedAsks.Count - 1; i++) { var currentOrder = tContext.CurrentOrders.OrderedAsks[i]; if (currentOrder.Price > tContext.LowestAskLimitPrice) { tContext.Price = currentOrder.Price; decimal idealAmount = AskOrderAmountExpression.Evaluate(tContext, tContext); //Cleaning: if the order span exceeds the previous order span //by more than the defined canceling rate, cancel the order if ((i > 1 && (tContext.CurrentOrders.OrderedAsks[i].Price - tContext.CurrentOrders.OrderedAsks[i - 1].Price) / (tContext.CurrentOrders.OrderedAsks[i - 1].Price - tContext.CurrentOrders.OrderedAsks[i - 2].Price) < this.CancelOrderLimitRate / 100m)) { tContext.NewOrders.CancelExistingOrders(currentOrder); } else if (currentOrder.Amount < idealAmount * AdjustOrderLimitRate / 100m) { var newOrder = new Order { OrderType = OrderType.Sell, Price = currentOrder.Price, Amount = idealAmount }; //new order amount is the difference between ideal amount and current amount tContext.NewOrders.CancelExistingOrders(currentOrder); tContext.NewOrders.Orders.Add(newOrder); } } } if (tContext.NewOrders.Orders.Count == 0 && tContext.NewOrders.PrimaryBalance * tContext.Market.Ticker.Last > tContext.CurrentOrders.HighestAsk.Value * VolumeGrowthLimitFactor) { //if their are still btcs available and their amount exceeds the strategy limit, increase the higher order var newOrder = new Order { OrderType = OrderType.Sell, Price = tContext.CurrentOrders.HighestAsk.Price, Amount = tContext.CurrentOrders.HighestAsk.Amount * (1 + this.VolumeGrowthRate / 100m) }; tContext.NewOrders.CancelExistingOrders(tContext.CurrentOrders.HighestAsk); tContext.NewOrders.Orders.Add(newOrder); } } } // Then we deal with Bids //todo: that should be symetrical thus abstracted as such if (!this.NoBids) { if (tContext.CurrentOrders.OrderedBids.Count == 0) { if (this.AccountForTrend || tContext.LastTrend != TradingTrend.Bid) { // There is no bid order yet/anymore, define a single new bid order //Compute price from current ticker and strategy var newLowBidPrice = tContext.Market.Ticker.Last * 100m / (DefaultBandWidthRate + 100m); var newOrder = new Order() { OrderType = OrderType.Buy, Price = newLowBidPrice, //compute amount from available balance and strategy Amount = (tContext.NewOrders.SecondaryBalance / newLowBidPrice) * DefaultMaxOrderValueRate / 100m }; tContext.NewOrders.Orders.Add(newOrder); } } // else: There are bid orders already, we'll base new orders according to the existing else if (tContext.CurrentOrders.LowestBid.Price > tContext.Market.Ticker.Last * 100m / (MinBandWidthRate + 100m) || tContext.CurrentOrders.LowestBid.Price < tContext.Market.Ticker.Last * 100m / (MaxBandWidthRate + 100m)) { // The band is not within defined bound: clear existing orders in order to define a new band tContext.NewOrders.CancelExistingOrders(tContext.CurrentOrders.OrderedBids.ToArray()); } else if (tContext.NewOrders.SecondaryBalance < tContext.CurrentOrders.LowestBid.Value * VolumeResetLimitFactor) { //the amount of available resource is too low for the existing band: clear orders to define a new band tContext.NewOrders.CancelExistingOrders(tContext.CurrentOrders.OrderedBids.ToArray()); } else { //we start with new low orders: have we got new orders to issue ? if (!AccountForTrend || tContext.LastTrend != TradingTrend.Bid || tContext.CurrentOrders.OrderedBids.Count < 2) { decimal newPrice, limitPrice; SimpleExpression <Decimal> pricingExpression; var sign = (int)TradingBandDirection; if (TradingBandDirection == TradingBandDirection.Outwards) { pricingExpression = NextBidOrderPriceExpression; newPrice = tContext.HighestBidLimitPrice; limitPrice = tContext.HighestBid.Price; } else { pricingExpression = MaxBidOrderPriceExpression; newPrice = pricingExpression.Evaluate(tContext, tContext); limitPrice = tContext.HighestBidLimitPrice; } //How close are we to the lowest limit ask price? safetyCounter = 0; while (newPrice > 0 && sign * newPrice > sign * limitPrice && safetyCounter < 500) { safetyCounter += 1; // We are within the authorized inner band , place new order var newOrder = new Order { OrderType = OrderType.Buy, Price = newPrice }; //set price to context to compute the new order amount tContext.Price = newPrice; newOrder.Amount = BidOrderAmountExpression.Evaluate(tContext, tContext); if (TradingBandDirection == TradingBandDirection.Inwards) { tContext.NewOrders.Orders.Add(newOrder); } newPrice = pricingExpression.Evaluate(tContext, tContext); if (TradingBandDirection == TradingBandDirection.Outwards && sign * newPrice > sign * limitPrice) { tContext.NewOrders.Orders.Add(newOrder); } } } //then we check existing orders for cancelling or increasing for (var i = 0; i <= tContext.CurrentOrders.OrderedBids.Count - 1; i++) { var currentOrder = tContext.CurrentOrders.OrderedBids[i]; if (currentOrder.Price < tContext.HighestBidLimitPrice) { tContext.Price = currentOrder.Price; decimal idealAmount = BidOrderAmountExpression.Evaluate(tContext, tContext); //Cleaning: if the order span exceeds the previous order span //by more than the defined canceling rate, cancel the order if ((i < tContext.CurrentOrders.OrderedBids.Count - 2 && (tContext.CurrentOrders.OrderedBids[i + 1].Price - tContext.CurrentOrders.OrderedBids[i].Price) / (tContext.CurrentOrders.OrderedBids[i + 2].Price - tContext.CurrentOrders.OrderedBids[i + 1].Price) < this.CancelOrderLimitRate / 100m)) { tContext.NewOrders.CancelExistingOrders(currentOrder); } else if (currentOrder.Amount < idealAmount * AdjustOrderLimitRate / 100m) { var newOrder = new Order { OrderType = OrderType.Buy, Price = currentOrder.Price, Amount = idealAmount }; //new order amount is the difference between ideal amount and current amount tContext.NewOrders.CancelExistingOrders(currentOrder); tContext.NewOrders.Orders.Add(newOrder); } } } if (tContext.NewOrders.Orders.Count == 0 && tContext.NewOrders.SecondaryBalance > tContext.CurrentOrders.LowestBid.Value * VolumeGrowthLimitFactor) { //if their are still resources available and their amount exceeds the strategy limit, increase the highest order var newOrder = new Order { OrderType = OrderType.Buy, Price = tContext.CurrentOrders.LowestBid.Price, Amount = tContext.CurrentOrders.LowestBid.Amount * (1 + this.VolumeGrowthRate / 100m) }; tContext.NewOrders.CancelExistingOrders(tContext.CurrentOrders.LowestBid); tContext.NewOrders.Orders.Add(newOrder); } } } }