Пример #1
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);
        }
Пример #2
0
        public static void LoadSystemSettings(RBBotContext dbContext)
        {
            //
            string preferredCode = SettingHelper.GetSystemSetting("PreferedCryptoCurrency");

            PreferredCyptoCurrency             = dbContext.Currencies.Where(x => x.Code == preferredCode).Single();
            MinimumTradeOpportunityPercent     = Convert.ToDecimal(SettingHelper.GetSystemSetting("MinimumTradeOpportunityPercent"));
            OpportunityTimeoutInSeconds        = Convert.ToInt32(SettingHelper.GetSystemSetting("OpportunityTimeoutInSeconds"));
            ExchangeConnectionTimeoutInSeconds = Convert.ToInt32(SettingHelper.GetSystemSetting("ExchangeConnectionTimeoutInSeconds"));
        }
Пример #3
0
        /// <summary>
        /// On market price change this is called to persist the information to db.
        /// </summary>
        /// <param name="change"></param>
        public async Task OnMarketPriceChangeAsync(PriceChangeEvent change)
        {
            // Save to database.
            using (var ctx = new RBBotContext())
            {
                ctx.MarketPrices.Add(new Models.MarketPrice()
                {
                    ExchangeTradePairId = change.ExchangeTradePair.Id,
                    Price     = change.Price,
                    Timestamp = change.UtcTime
                });

                // Write to console.
                //Console.WriteLine($"Price Change on {change.ExchangeTradePair.Exchange.Name} for {change.ExchangeTradePair.TradePair.FromCurrency.Code} - {change.ExchangeTradePair.TradePair.ToCurrency.Code}. New Price: {change.Price}");

                await ctx.SaveChangesAsync();
            }
        }
Пример #4
0
        public async Task ExecuteAction(bool simulate)
        {
            // Decrement from account, increment to account.
            this.FromAccount.Balance -= this.EstimatedCost + this.TransferAmount;
            this.ToAccount.Balance   += this.TransferAmount;

            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!!
            }
        }
Пример #5
0
        public CycleFinder(Exchange exchange)
        {
            this.exchange = exchange;

            currencyDict = new Dictionary <int, Currency>();
            using (var ctx = new RBBotContext())
            {
                currencyDict = ctx.Currencies.ToDictionary(x => x.Id, y => y);
            }

            // Get an array of the trade pairs in a jagged array
            graph = new int[exchange.ExchangeTradePairs.Count, 2];

            for (int i = 0; i < exchange.ExchangeTradePairs.Count; i++)
            {
                graph[i, 0] = exchange.ExchangeTradePairs.ElementAt(i).TradePair.FromCurrencyId;
                graph[i, 1] = exchange.ExchangeTradePairs.ElementAt(i).TradePair.ToCurrencyId;
            }
        }
Пример #6
0
        /// <summary>
        /// On market price change this is called to persist the information to db.
        /// </summary>
        /// <param name="change"></param>
        public async Task <IEnumerable <Opportunity> > OnMarketPriceChangeAsync(ExchangeTradePair change)
        {
            // Save to database.
            using (var ctx = new RBBotContext())
            {
                ctx.MarketPrices.Add(new Models.MarketPrice()
                {
                    ExchangeTradePairId = change.Id,
                    Price     = change.LatestPrice,
                    Timestamp = change.LatestUpdate
                });

                // Write to console.
                //Console.WriteLine($"Price Change on {change.ExchangeTradePair.Exchange.Name} for {change.ExchangeTradePair.TradePair.FromCurrency.Code} - {change.ExchangeTradePair.TradePair.ToCurrency.Code}. New Price: {change.Price}");

                await ctx.SaveChangesAsync();

                // Always return null! There's no opportunity in the observer.
                return(new Opportunity[] { });
            }
        }
Пример #7
0
        /// <summary>
        /// This method is used to actually execute the opportunity
        /// </summary>
        /// <param name="simulate"></param>
        public async Task ExecuteOpportunity(bool simulate = true)
        {
            // Loop through all actions.
            foreach (var syncActions in this.Actions)
            {
                // Wait all tasks to finish, but launch in parallel!
                Task.WaitAll(syncActions.Select(x => x.ExecuteAction(simulate)).ToArray());
            }

            using (var ctx = new RBBotContext())
            {
                if (this.OpportunityModel != null)
                {
                    return;                                // Should never be the case, but never know.
                }
#warning this is incomplete!!
                lock (this.OpportunityModel)
                {
                }
            }
        }
Пример #8
0
        private static async Task <TradeOpportunity> GetOrUpdateTradeOpportunity(Opportunity opportunity, bool IsSimulation)
        {
            // Update requirements and maximum possible trade.
            var requirements = opportunity.UpdateRequirementsAndAmount().ToList();

            //
            string stateCode = opportunity.RequirementsMet ? "RQ-MET" : "RQ-MISSING";

            decimal oppValue = opportunity.GetMarginValuePercent();

            // Create the trade value;
            var newTradeValue = new TradeOpportunityValue()
            {
                PotentialMargin         = oppValue,
                Timestamp               = DateTime.UtcNow,
                TradeOpportunityStateId = TradeOpportunityState.States.Single(x => x.Code == stateCode).Id
            };

            // If the oppvalue is below treshold and doesn't exist yet, then ignore it. Else stop it.
            if (oppValue < SystemSetting.MinimumTradeOpportunityPercent)
            {
                TradeOpportunity tradOpp = null;
                tradeOpportunities.TryGetValue(opportunity.UniqueIdentifier, out tradOpp);

                if (tradOpp == null)
                {
                    return(null);
                }
                else
                {
                    var belowThresholdState = TradeOpportunityState.States.Single(x => x.Code == "EXP-BELOW");
                    newTradeValue.TradeOpportunityStateId = belowThresholdState.Id;
                    await EndTradeOpportunity(tradOpp, belowThresholdState, newTradeValue);

                    return(null);
                }
            }


            // Try getting the TradeOpp from the dictionary. If it doesn't exist, then construct it now
            var isNewOpportunity = false;
            var tradeOpp         = tradeOpportunities.GetOrAdd(opportunity.UniqueIdentifier, (key) =>
            {
                isNewOpportunity = true;
                return(new TradeOpportunity()
                {
                    CurrencyId = opportunity.OpportunityBaseCurrency.Id,
                    IsExecuted = false,
                    IsSimulation = IsSimulation,
                    StartTime = DateTime.UtcNow,
                    TradeOpportunityTypeId = TradeOpportunityType.Types.Single(x => x.Code == opportunity.TypeCode).Id,
                    TradeOpportunityStateId = TradeOpportunityState.States.Single(x => x.Code == stateCode).Id,
                    Description = opportunity.UniqueIdentifier,
                    LatestOpportunity = opportunity,
                    LastestUpdate = DateTime.UtcNow
                });
            }
                                                               );

            tradeOpp.LatestOpportunity = opportunity;
            tradeOpp.LastestUpdate     = DateTime.UtcNow;


            // Before writing, we lock the semaphore.
            await tradeOpp.LockingSemaphore.WaitAsync(); // Lock

            try
            {
                // Otherwise the opportunity is still valid.
                // If this is a new opportunity, then we definitely need to save to DB.
                if (isNewOpportunity)
                {
                    using (var ctx = new RBBotContext())
                    {
                        requirements.ForEach(x => { x.TradeOpportunity = tradeOpp; tradeOpp.TradeOpportunityRequirements.Add(x); });
                        tradeOpp.TradeOpportunityValues.Add(newTradeValue);
                        newTradeValue.TradeOpportunity = tradeOpp;

                        ctx.TradeOpportunities.Add(tradeOpp);
                        ctx.TradeOpportunityRequirements.AddRange(requirements);
                        ctx.TradeOpportunityValues.Add(newTradeValue);


                        await ctx.SaveChangesAsync();
                    }
                }
                else
                {
                    // Else we take the requirements and see if anything changed.
                    var requirementsToAdd = new List <TradeOpportunityRequirement>();

                    foreach (var req in requirements)
                    {
                        var toReq = tradeOpp.TradeOpportunityRequirements.Where(x => x.ItemIdentifier == req.ItemIdentifier && x.TradeOpportunityRequirementType == req.TradeOpportunityRequirementType).OrderBy(x => x.Timestamp).LastOrDefault();

                        if (toReq == null || toReq.RequirementMet != req.RequirementMet)
                        {
                            requirementsToAdd.Add(req);
                            req.TradeOpportunityId = tradeOpp.Id;
                        }
                    }

                    newTradeValue.TradeOpportunityId = tradeOpp.Id;

                    using (var ctx = new RBBotContext())
                    {
                        ctx.TradeOpportunityRequirements.AddRange(requirementsToAdd);
                        ctx.TradeOpportunityValues.Add(newTradeValue);
                        await ctx.SaveChangesAsync();
                    }
                }
            }
            finally
            {
                tradeOpp.LockingSemaphore.Release();
            }


            // Return the trade opportunity object.
            return(tradeOpp);
        }
Пример #9
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();
            }
        }
Пример #10
0
        private static async Task SynchronizeAccounts(IExchangeTrader exchangeIntegration, RBBotContext dbContext)
        {
            Exchange exchangeModel = exchangeIntegration.Exchange;

            // Get the balances from the exchange integration
            var exchangebalances = (await exchangeIntegration.GetBalancesAsync()).ToDictionary(x => x.CurrencyCode, y => y);

            // Get the exchange's trading accounts.
            var existingAccounts = exchangeModel.TradeAccounts.ToDictionary(x => x.Currency.Code, y => y);

            // If the account exists already, then update.
            existingAccounts.Where(x => exchangebalances.Keys.Contains(x.Key)).ToList().ForEach(x =>
            {
                var exCurr     = exchangebalances[x.Key];
                var acc        = existingAccounts[x.Key];
                acc.Balance    = exCurr.Balance;
                acc.LastUpdate = exCurr.Timestamp;

                if (exCurr.ExchangeIdentifier != null)
                {
                    acc.ExchangeIdentifier = exCurr.ExchangeIdentifier;
                }
                if (exCurr.Address != null)
                {
                    acc.Address = exCurr.Address;
                }
            });

            // If the account doesn't exist, then create it.
            exchangebalances.Keys.Where(x => !existingAccounts.Keys.Contains(x)).ToList().ForEach(x =>
            {
                var b            = exchangebalances[x];
                TradeAccount acc = new TradeAccount()
                {
                    Address            = b.Address,
                    Balance            = b.Balance,
                    Exchange           = exchangeModel,
                    ExchangeIdentifier = b.ExchangeIdentifier,
                    LastUpdate         = b.Timestamp,
                    Currency           = dbContext.Currencies.Where(c => c.Code == b.CurrencyCode).Single()
                };

                dbContext.TradeAccounts.Add(acc);
            });
        }
Пример #11
0
        public static async Task InitializeEngine(IMarketPriceObserver[] priceObservers)
        {
            IList <Exchange> exchangeModels = null;
            IList <Setting>  settings       = null;
            List <IExchange> integrations   = null;

            // Get all exchangeModels. We need them to construct the integrations.
            using (var ctx = new RBBotContext())
            {
                // Load the exchanges and all the stuff associated with them
                exchangeModels = ctx.Exchanges
                                 .Include(x => x.ExchangeState)
                                 .Include(x => x.Settings)
                                 .Include(x => x.ExchangeTradePairs.Select(y => y.ExchangeTradePairState))
                                 .Include(x => x.ExchangeTradePairs.Select(y => y.TradePair).Select(z => z.FromCurrency))
                                 .Include(x => x.ExchangeTradePairs.Select(y => y.TradePair).Select(z => z.ToCurrency))
                                 .Where(x => x.ExchangeState.Code != "OFF") // Don't get offline exchanges!
                                 .ToList();

                // Get / cache the settings.
                settings = ctx.Settings.ToList();

                // Now since I'm lazy, i first put setting unencrypted in db, and then encrypt them here.
                if (settings.Where(x => x.IsEncrypted == false && x.ShouldBeEncrypted == true).Any(x => { x.EncryptSetting(); return(true); }))
                {
                    ctx.SaveChanges();
                }

                // Now initialize the setting helper with all settings!
                SettingHelper.InitializeSettings(settings.ToArray());


                // Initialize all exchanges and their integrations.
                var ccExchangeIds = settings.Where(x => x.Name == "ReadFromCryptoCompare" && x.Value.ToLower() == "true").Select(x => x.ExchangeId).ToList();
                var ccExchanges   = exchangeModels.Where(x => ccExchangeIds.Contains(x.Id)).ToList();

                integrations = new List <Exchanges.IExchange>();
                integrations.Add(new CryptoCompareIntegration(priceObservers, ccExchanges.ToArray()));
                integrations.Add(new BitflyerIntegration(priceObservers, new[] { exchangeModels.Single(x => x.Name == "Bitflyer") }));
                integrations.Add(new GDAXIntegration(priceObservers, new[] { exchangeModels.Single(x => x.Name == "GDAX") }));
                //integrations.Add(new OKCoinComIntegration(priceObservers, new[] { exchangeModels.Single(x => x.Name == "OKCoin.com") }));
                //integrations.Add(new OKCoinCNIntegration(priceObservers, new[] { exchangeModels.Single(x => x.Name == "OKCoin.cn") }));

                integrations.Add(new PoloniexIntegration(exchangeModels.Single(x => x.Name == "Poloniex")));
                integrations.Add(new KrakenIntegration(exchangeModels.Single(x => x.Name == "Kraken")));


                // Synchronize all the trading accounts.
                var tradingExchanges = integrations.Where(x => x is IExchangeTrader).Select(x => x as IExchangeTrader).ToList();
                foreach (var te in tradingExchanges)
                {
                    await SynchronizeAccounts(te, ctx);
                }
                await ctx.SaveChangesAsync();
            }

            var readerExchanges = integrations.Where(x => x is IExchangePriceReader).Select(x => x as IExchangePriceReader).ToList();

            foreach (var e in readerExchanges)
            {
                await e.InitializeExchangePriceProcessingAsync();
            }
        }
Пример #12
0
        public static async Task <IExchange[]> InitializeEngine(bool isSimulation = true)
        {
            IList <Exchange> exchangeModels = null;
            IList <Setting>  settings       = null;
            List <IExchange> integrations   = null;

            // Get all exchangeModels. We need them to construct the integrations.
            using (var ctx = new RBBotContext())
            {
                // Load the exchanges and all the stuff associated with them
                exchangeModels = ctx.Exchanges
                                 .Include(x => x.ExchangeState)
                                 .Include(x => x.Settings)
                                 .Include(x => x.TradeAccounts)
                                 .Include(x => x.ExchangeTradePairs.Select(y => y.ExchangeTradePairState))
                                 .Include(x => x.ExchangeTradePairs.Select(y => y.TradePair).Select(z => z.FromCurrency))
                                 .Include(x => x.ExchangeTradePairs.Select(y => y.TradePair).Select(z => z.ToCurrency))
                                 .Where(x => x.ExchangeState.Code != "OFF") // Don't get offline exchanges!
                                 .ToList();

                // Get / cache the settings.
                settings = ctx.Settings.ToList();


                // Now since I'm lazy, i first put setting unencrypted in db, and then encrypt them here.
                if (settings.Where(x => x.IsEncrypted == false && x.ShouldBeEncrypted == true).Any(x => { x.EncryptSetting(); return(true); }))
                {
                    ctx.SaveChanges();
                }

                // Now initialize the setting helper with all settings!
                SettingHelper.InitializeSettings(settings.ToArray());

                // Initialize system settings.
                SystemSetting.LoadSystemSettings(ctx);


                // Initialize all exchanges and their integrations.
                var ccExchangeIds = settings.Where(x => x.Name == "ReadFromCryptoCompare" && x.Value.ToLower() == "true").Select(x => x.ExchangeId).ToList();
                var ccExchanges   = exchangeModels.Where(x => ccExchangeIds.Contains(x.Id)).ToList();

                integrations = new List <Exchanges.IExchange>();
                integrations.Add(new CryptoCompareIntegration(ccExchanges.ToArray()));
                integrations.Add(new BitflyerIntegration(new[] { exchangeModels.Single(x => x.Name == "Bitflyer") }));
                integrations.Add(new GDAXIntegration(new[] { exchangeModels.Single(x => x.Name == "GDAX") }));
                //integrations.Add(new OKCoinComIntegration(priceObservers, new[] { exchangeModels.Single(x => x.Name == "OKCoin.com") }));
                //integrations.Add(new OKCoinCNIntegration(priceObservers, new[] { exchangeModels.Single(x => x.Name == "OKCoin.cn") }));

                integrations.Add(new PoloniexIntegration(exchangeModels.Single(x => x.Name == "Poloniex")));
                integrations.Add(new KrakenIntegration(exchangeModels.Single(x => x.Name == "Kraken")));



                // Cache other lookups
                TradeOpportunityRequirementType.RequirementTypes = ctx.TradeOpportunityRequirementTypes.ToArray();
                TradeOpportunityState.States = ctx.TradeOpportunityStates.ToArray();
                TradeOpportunityType.Types   = ctx.TradeOpportunityTypes.ToArray();

                // Initialize the price cache;
                TradePriceIndex.Initialize(exchangeModels.ToArray(), ctx.TradePairs.ToArray());



                // Synchronize all the trading accounts.
                var tradingExchanges = integrations.Where(x => x is IExchangeTrader).Select(x => x as IExchangeTrader).ToList();
                foreach (var te in tradingExchanges)
                {
                    te.Exchange.TradingIntegration = te; // Set the trading integration.
                    await SynchronizeAccounts(te, ctx, isSimulation);
                }
                await ctx.SaveChangesAsync();
            }

            var readerExchanges = integrations.Where(x => x is IExchangePriceReader).Select(x => x as IExchangePriceReader).ToList();

            foreach (var e in readerExchanges)
            {
                Task.Run(async() => e.InitializeExchangePriceProcessingAsync());
            }

            // Return list of discovered integrations. These will be used to observe the the pricing data.
            return(integrations.ToArray());
        }
Пример #13
0
        internal async Task UpdateOpportunity(decimal newMarginValue)
        {
            this.CurrentValue = newMarginValue;

            // the opportunity is only considered started on first non-zero value!
            if (newMarginValue == 0m)
            {
                return;
            }

            using (var ctx = new RBBotContext())
            {
                if (this.OpportunityModel == null)
                {
                    this.OpportunityModel = new TradeOpportunity()
                    {
                        CurrencyId             = this.OpportunityBaseCurrency.Id,
                        StartTime              = DateTime.UtcNow,
                        IsExecuted             = false,
                        TradeOpportunityTypeId = ctx.TradeOpportunityTypes.Single(x => x.Code == this.TypeCode).Id
                    };


                    lock (this.OpportunityModel)
                    {
                        // Add it to the context.
                        ctx.TradeOpportunities.Add(this.OpportunityModel);
                        ctx.SaveChanges(); // Don't execute this async so we avoid having the children created before the parent!
                    }
                }

                var newTradeValue = new TradeOpportunityValue()
                {
                    PotentialMargin    = newMarginValue,
                    Timestamp          = DateTime.UtcNow,
                    TradeOpportunityId = this.OpportunityModel.Id
                };


                ctx.TradeOpportunityValues.Add(newTradeValue);
                //this.OpportunityModel.TradeOpportunityValues.Add(newTradeValue);
                //ctx.Entry(this.OpportunityModel).State = System.Data.Entity.EntityState.Modified;
                //ctx.TradeOpportunityValues.Add(newTradeValue);

                try
                {
                    await ctx.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error saving opportunity to database: ", ex.ToString());
                }


                // async save to db and return
                //await ctx.SaveChangesAsync();

                //
                await OpportunityScoreEngine.UpdateOpportunityValue(this);
            }
        }