Esempio n. 1
0
        public override Task <TradeActionResponse> DoTradeAction(TradeActionRequest request, ServerCallContext context)
        {
            var response = new TradeActionResponse();

            switch (request.ActionName)
            {
            case StaticData.Constants._Actions._Trade.GET:
                response.Trade = GetDetailedTradeView(request.TradeUserInfo, context);
                var tradeUserState = GetTradeUserState(request.TradeUserInfo, context).Result;

                if (tradeUserState.Description.Length == 0)
                {
                    // add IOI
                    request.TradeUserInfo.State = new State {
                        Description = _States._TradeUser.IOI
                    };
                    AddTradeUserState(request.TradeUserInfo, context);
                }
                response.NextActions = GetTradeActions(request.TradeUserInfo, context).Result;


                break;

            default:
                break;
            }

            return(Task.FromResult(response));
        }
Esempio n. 2
0
        public async Task <TradeActionResponse> ExecuteAction(bool simulate)
        {
            // Decrement from account, increment to account.
            this.FromAccount.Balance -= this.EstimatedCost + this.TransactionAmount;
            this.ToAccount.Balance   += this.TransactionAmount;

            var resp = new TradeActionResponse()
            {
                ExecutionSuccessful = true,
                Transactions        = null
            };

            using (var ctx = new RBBotContext())
            {
                ctx.Entry(this.FromAccount).State = System.Data.Entity.EntityState.Modified;
                ctx.Entry(this.ToAccount).State   = System.Data.Entity.EntityState.Modified;
                await ctx.SaveChangesAsync();

                if (!simulate)
                {
#warning Still to implement the actual thing!!
                }

                throw new NotImplementedException();
            }

            return(resp);
        }
Esempio n. 3
0
        public async Task <TradeActionResponse> ExecuteAction(bool simulate)
        {
            // Either from or to account must be the base currency. Else throw exception.
            if (this.FromAccount.Currency != this.BaseCurrency && this.ToAccount.Currency != this.BaseCurrency)
            {
                throw new NotSupportedException($"It is not supported to have trade actions where {this.BaseCurrency.Code} is not involved");
            }

            var resp = new TradeActionResponse();

            // This is where money is spent... be cautious
            ExchangeOrderResponse orderResponse = null;

            if (simulate == false)
            {
                orderResponse = await TradingIntegration.PlaceOrder(this.OrderType, this.TransactionAmount, this.BaseCurrency, this.TradePair);
            }
            else
            {
                orderResponse = new ExchangeOrderResponse()
                {
                    Success = true, ExternalTransactionId = "Simulation-Tx"
                };
                orderResponse.Fee = TradingIntegration.EstimateTransactionFee(this.OrderType, this.TransactionAmount, this.BaseCurrency, this.TradePair);
            }


            if (orderResponse.Success == false)
            {
                resp.ExecutionSuccessful = false;
                return(resp);
            }
            ;  // Return nothing if there was a problem.


            // If the order type is a sell, then the FromAccount decreases and the ToAccount balance increases.
            // This means that if we're selling, then we'll have less ETH (from amount) and more BTC (to amount)
            // Therefore the from amount difference is just the TransactionAmount and +ve/-ve according to whether its a buy or sell.
            var fromAmount = this.TransactionAmount * (this.OrderType == ExchangeOrderType.Buy ? 1 : -1);
            var toAmount   = -1 * fromAmount;

            //
            var exchangeRate = this.TradePair.LatestPrice;

            // Now we do the currency conversion. We'll do the conversion on the non-preferred currency.
            if (this.FromAccount.Currency == this.BaseCurrency)
            {
                toAmount = toAmount / exchangeRate;
            }
            else
            {
                fromAmount = fromAmount / exchangeRate;
            }


            var fromAccountFee = orderResponse.Fee.Currency == this.TradePair.TradePair.FromCurrency ? orderResponse.Fee.Amount : 0m;
            var toAccountFee   = orderResponse.Fee.Currency == this.TradePair.TradePair.ToCurrency ? orderResponse.Fee.Amount : 0m;

            var fromAccountBalanceBefore = FromAccount.Balance;
            var toAccountBalanceBefore   = ToAccount.Balance;
            var fromAccountBalanceAfter  = fromAccountBalanceBefore + fromAmount - fromAccountFee;
            var toAccountBalanceAfter    = toAccountBalanceBefore + toAmount - toAccountFee;

            var tx = new TradeOpportunityTransaction()
            {
                CreationDate          = DateTime.UtcNow,
                ExchangeRate          = exchangeRate,
                FromAccountId         = FromAccount.Id,
                ToAccountId           = ToAccount.Id,
                ExternalTransactionId = orderResponse.ExternalTransactionId,
                ExecutedOnExchangeId  = this.TradePair.Exchange.Id,
                IsReal                             = !simulate,
                FromAccountFee                     = fromAccountFee,
                ToAccountFee                       = toAccountFee,
                FromAmount                         = fromAmount,
                ToAmount                           = toAmount,
                FromAccountBalanceBeforeTx         = fromAccountBalanceBefore,
                ToAccountBalanceBeforeTx           = toAccountBalanceBefore,
                EstimatedFromAccountBalanceAfterTx = fromAccountBalanceAfter,
                EstimatedToAccountBalanceAfterTx   = toAccountBalanceAfter,
            };

            FromAccount.Balance    = fromAccountBalanceAfter;
            ToAccount.Balance      = toAccountBalanceAfter;
            FromAccount.LastUpdate = DateTime.UtcNow;
            ToAccount.LastUpdate   = DateTime.UtcNow;

            // Return the response.
            resp.Transactions        = new TradeOpportunityTransaction[] { tx };
            resp.ExecutionSuccessful = true;

            return(resp);
        }
Esempio n. 4
0
        public static async Task EndTradeOpportunity(TradeOpportunity opportunity, TradeOpportunityState finalState, TradeOpportunityValue finalOpportunityValue = null, TradeActionResponse tradeActionResponse = null)
        {
            // Note: This was initially written in a way that I first remove the trade opp from the concurrent dictionary and then write to the DB.
            // It was wrong as by the time we got back a response from the db, other same opportunities were being written! This caused a lot of same opportunities to be written!
            // Therefore what we do here is first we singal the removal from the database and only once this is done we try to remove it from the concurrent dictionary.
            // For this reason the trade opportunity is immediately locked.


            // This is the part we persist to the db. We first wait for
            // any possible semaphore on the opportunity and release it as soon as we're done.

            await opportunity.LockingSemaphore.WaitAsync();


            // It might have happened that this opportunity was already written to the db. Ignore this call.
            if (opportunity.IsDbExecutedWritten)
            {
                return;
            }

            try
            {
                // Persist to db
                using (var ctx = new RBBotContext())
                {
                    opportunity.TradeOpportunityStateId = finalState.Id;
                    opportunity.EndTime = DateTime.UtcNow;

                    // If a final value is specified, add it now.
                    if (finalOpportunityValue != null)
                    {
                        finalOpportunityValue.TradeOpportunityId = opportunity.Id;
                        ctx.TradeOpportunityValues.Add(finalOpportunityValue);
                    }

                    // With transactions we also look into the accounts and update them.
                    if (tradeActionResponse != null)
                    {
                        tradeActionResponse.Transactions.ToList().ForEach(x => x.TradeOpportunity = opportunity);
                        ctx.TradeOpportunityTransactions.AddRange(tradeActionResponse.Transactions);

                        foreach (var acc in opportunity.LatestOpportunity.GetAffectedAccounts())
                        {
                            ctx.TradeAccounts.Attach(acc);
                            ctx.Entry(acc).State = System.Data.Entity.EntityState.Modified;
                        }
                    }

                    ctx.TradeOpportunities.Attach(opportunity);
                    ctx.Entry(opportunity).State = System.Data.Entity.EntityState.Modified;

                    await ctx.SaveChangesAsync();

                    opportunity.IsDbExecutedWritten = true; // This is an unmapped property that is used to make sure that if by any chance this trade opportunity is tried to be ended again, it won't succeed!

                    // Now that we've written to the db, try removing it from the concurrent dictionary.
                    TradeOpportunity time           = null;
                    bool             removedSuccess = tradeOpportunities.TryRemove(opportunity.LatestOpportunity.UniqueIdentifier, out time);

                    if ((removedSuccess) && (OnOpportunityExpired != null))  // If the opportunity could be removed, then raise event!.
                    {
                        OnOpportunityExpired(opportunity);
                    }
                }
            }
            finally
            {
                opportunity.LockingSemaphore.Release();
            }
        }