Beispiel #1
0
        /// <summary>
        /// Importa un archivo DDP en formato XML a la base de datos
        /// </summary>
        /// <param name="stream">Stream de memoria del archivo</param>
        public DateTime Import(XmlDocument ddpxml, DDPVersion ddpVersion)
        {
            DateTime      pubDate = DateTime.UtcNow;
            DBDataContext context = null;

            try
            {
                context = new DBDataContext(Config.ConnectionString);

                //---------------------------------------------------
                XmlNamespaceManager nsmanager = new XmlNamespaceManager(ddpxml.NameTable);
                nsmanager.AddNamespace("lr", "http://gisis.imo.org/XML/LRIT/ddp/2008");
                //---------------------------------------------------

                //Hack-o-mati: Asociation of contracting goverment
                Dictionary <ContractingGoverment, ContractingConfig> goverments = new Dictionary <ContractingGoverment, ContractingConfig>();

                //Just for return, do not use here.
                pubDate = DateTime.Parse(ddpxml.SelectSingleNode("/lr:DataDistributionPlan", nsmanager).Attributes["regularVersionImplementationAt"].Value);

                readCGS("/lr:DataDistributionPlan/lr:ContractingGovernment", ref goverments, ref ddpxml, ref nsmanager);
                readCGS("/lr:DataDistributionPlan/lr:Territory", ref goverments, ref ddpxml, ref nsmanager);

                var cgda = new ContractingGovermentDataAccess(context);
                var pda  = new PlaceDataAccess(context);
                var soda = new StandingOrderDataAccess(context);
                var ssda = new SARServiceDataAccess(context);
                //var exda = new ExclusionDataAccess(context);

                //cgda.DropAll();

                foreach (KeyValuePair <ContractingGoverment, ContractingConfig> kv in goverments)
                {
                    kv.Key.DDPVersionId = ddpVersion.Id;
                    int gId = cgda.Create(kv.Key);

                    foreach (Place p in kv.Value.places)
                    {
                        p.ContractingGovermentId = gId;
                    }

                    foreach (SARService ss in kv.Value.sarservice)
                    {
                        ss.ContractingGovermentId = gId;
                    }

                    //foreach (Exclusion excl in kv.Value.exclusions)
                    //  excl.ContractingGoverment = gId;

                    log.Debug(string.Format("{2}: Key:{0}, Value{1}", kv.Key.Name, kv.Value.places.Count, kv.Key.Id));

                    pda.Create(kv.Value.places.ToArray());
                    //exda.Create(kv.Value.exclusions.ToArray());

                    ssda.Create(kv.Value.sarservice.ToArray());

                    //Places with ids
                    List <Place> places = pda.GetAll(ddpVersion.regularVer + ":" + ddpVersion.inmediateVer);

                    //Standing orders
                    string  path          = string.Format("/lr:DataDistributionPlan/lr:CoastalStateStandingOrders/lr:StandingOrder[@contractingGovernmentID='{0}']", kv.Key.LRITId);
                    XmlNode standingOrder = ddpxml.SelectSingleNode(path, nsmanager);

                    if (standingOrder != null && !String.IsNullOrEmpty(standingOrder.InnerText))
                    {
                        foreach (string area in standingOrder.InnerText.Split(' '))
                        {
                            int id = getPlaceId(places, area);
                            if (id == -1)
                            {
                                continue;
                            }

                            StandingOrder so = new StandingOrder();
                            so.PlaceId = id;
                            kv.Value.standingOrders.Add(so);
                        }
                    }

                    //ES ACA
                    soda.Create(kv.Value.standingOrders.ToArray());
                }
            }
            catch (Exception ex)
            {
                if (context != null)
                {
                    context.Dispose();
                }

                throw new Exception("Unable to Import DDP File", ex);
            }
            finally
            {
                if (context != null)
                {
                    context.Dispose();
                }
            }

            return(pubDate);
        }
Beispiel #2
0
        public async Task <ActionResult <MarketOrderDTO> > PostMarketOrder(long quantity, string type)
        {
            // buy/sell quantity of bitcoin at lowest/highest price available
            User user = Utils.GetUserFromToken(_context, Request.Headers);

            if (user == null)
            {
                // would rather do this inside the GetUserFromToken function, but i don't know how to do that with this framework
                return(Unauthorized());
            }
            bool isBuy;
            IQueryable <StandingOrder> query;

            switch (type)
            {
            case "BUY":
                isBuy = true;
                query = from o in _context.Orders
                        where (o.isBuy == false) && (o.status == "LIVE") && (o.user_id != user.id)
                        orderby o.dollarRate ascending
                        select o;
                break;

            case "SELL":
                isBuy = false;
                query = from o in _context.Orders
                        where (o.isBuy == true) && (o.status == "LIVE") && (o.user_id != user.id)
                        orderby o.dollarRate descending
                        select o;
                break;

            default:
                return(BadRequest("type must be `BUY` or `SELL`"));
            }
            lock (OrdersController.tradeLock)
            {
                long remaining_quantity = quantity, money = 0;
                while (remaining_quantity > 0)
                {
                    StandingOrder standingOrder = query.FirstOrDefault();
                    if (standingOrder == null)
                    {
                        break;
                    }
                    User anotherUser = _context.Users.Find(standingOrder.user_id);
                    long canAfford;
                    if (isBuy)
                    {
                        canAfford = user.dollars / standingOrder.dollarRate; // integer division (rounding down)
                    }
                    else
                    {
                        canAfford = user.bitcoins;
                    }
                    if (canAfford == 0)
                    {
                        break;
                    }
                    long amount_trade = Math.Min(remaining_quantity, Math.Min(standingOrder.remainingBitcoinAmount, canAfford));
                    remaining_quantity -= amount_trade;
                    long money_trade = amount_trade * standingOrder.dollarRate;
                    money += money_trade;
                    standingOrder.remainingBitcoinAmount -= amount_trade;
                    if (standingOrder.remainingBitcoinAmount == 0)
                    {
                        standingOrder.status = "FULFILLED";
                    }
                    if (isBuy)
                    {
                        user.dollars        -= money_trade;
                        user.bitcoins       += amount_trade;
                        anotherUser.dollars += money_trade;
                    }
                    else
                    {
                        user.bitcoins        -= amount_trade;
                        user.dollars         += money_trade;
                        anotherUser.bitcoins += amount_trade;
                    }
                    _context.SaveChanges();
                }
                long    total_amount_traded = quantity - remaining_quantity;
                decimal average_rate        = total_amount_traded == 0 ? 0 : Decimal.Divide(money, total_amount_traded);
                return(new MarketOrderDTO(total_amount_traded, average_rate));
            }
        }
Beispiel #3
0
        public async System.Threading.Tasks.Task ComplexTest()
        {
            //taken from project definition

            (UsersController usersController, OrdersController ordersController, HttpContext httpContext) = setupControllers();

            //4 users set up balance
            UserDTO a = (await usersController.PostUser("A")).Value;
            UserDTO b = (await usersController.PostUser("B")).Value;
            UserDTO c = (await usersController.PostUser("C")).Value;
            UserDTO d = (await usersController.PostUser("D")).Value;

            httpContext.Request.Headers["token"] = a.token;
            await usersController.PutBalance("BTC", 1);

            httpContext.Request.Headers["token"] = b.token;
            await usersController.PutBalance("BTC", 10);

            httpContext.Request.Headers["token"] = c.token;
            await usersController.PutBalance("USD", 250000);

            httpContext.Request.Headers["token"] = d.token;
            await usersController.PutBalance("USD", 300000);

            // user a tries to post order, doesn't have enough tokens, gets more tokens and posts order again, this time succesfully
            httpContext.Request.Headers["token"] = a.token;
            var ao1 = (await ordersController.PostOrder(10, "SELL", 10000)).Result as BadRequestObjectResult;

            Assert.AreEqual(400, ao1.StatusCode);
            Assert.AreEqual("Not enough assets on account for this order", ao1.Value);
            await usersController.PutBalance("BTC", 10);

            StandingOrder ao2 = (await ordersController.PostOrder(10, "SELL", 10000)).Value;

            // B makes a standing order too
            httpContext.Request.Headers["token"] = b.token;
            var bo1 = (await ordersController.PostOrder(10, "SELL", 20000)).Value;

            // C makes a market order - check average price, balance
            httpContext.Request.Headers["token"] = c.token;
            MarketOrderDTO cm1 = (await ordersController.PostMarketOrder(15, "BUY")).Value;

            Assert.AreEqual(13333.33, (double)cm1.avg_price, 0.004);   // there is no AreEqual for decimal
            UserBalanceDTO cb1 = (await usersController.GetBalance()).Value;

            Assert.AreEqual(15, cb1.bitcoins);
            Assert.AreEqual(50000, cb1.dollars);

            //check existing standing orders
            httpContext.Request.Headers["token"] = a.token;
            ao2 = (await ordersController.GetOrder(ao2.id)).Value;
            Assert.AreEqual("FULFILLED", ao2.status);
            Assert.AreEqual(0, ao2.remainingBitcoinAmount);

            httpContext.Request.Headers["token"] = b.token;
            bo1 = (await ordersController.GetOrder(bo1.id)).Value;
            Assert.AreEqual("LIVE", bo1.status);
            Assert.AreEqual(5, bo1.remainingBitcoinAmount);

            // D makes a standing buy order thats cheaper than what B is selling for, and then makes another one but doesn't have enough money remaining

            httpContext.Request.Headers["token"] = d.token;
            StandingOrder do1 = (await ordersController.PostOrder(20, "BUY", 10000)).Value;
            var           do2 = (await ordersController.PostOrder(10, "BUY", 25000)).Result as BadRequestObjectResult;

            Assert.AreEqual(400, do2.StatusCode);
            Assert.AreEqual("Not enough assets on account for this order", do2.Value);

            // D then deletes the first order and remakes the second order, which is partially fulfilled

            do1 = (await ordersController.DeleteOrder(do1.id)).Value;
            Assert.AreEqual("CANCELLED", do1.status);
            StandingOrder do3 = (await ordersController.PostOrder(10, "BUY", 25000)).Value;

            Assert.AreEqual("LIVE", do3.status);
            Assert.AreEqual(5, do3.remainingBitcoinAmount);
            // since D bought 5 bitcoin at 20k (older standing order), they should have 100k less than at beginning, and onother 125k reserved their standing order
            UserBalanceDTO db = (await usersController.GetBalance()).Value;

            Assert.AreEqual(300000 - 100000 - 125000, db.dollars);
            Assert.AreEqual(5, db.bitcoins);

            // now checking balance and standing order status of B
            httpContext.Request.Headers["token"] = b.token;
            bo1 = (await ordersController.GetOrder(bo1.id)).Value;
            Assert.AreEqual("FULFILLED", bo1.status);
            UserBalanceDTO bb = (await usersController.GetBalance()).Value;

            Assert.AreEqual(0, bb.bitcoins);
            Assert.AreEqual(200000, bb.dollars);
        }
Beispiel #4
0
        public async Task <ActionResult <StandingOrder> > PostOrder(long quantity, string type, long limit_price)
        {
            // in this endpoint, we simultaneously create a standing order and try to fulfill it similarly to market order

            User user = Utils.GetUserFromToken(_context, Request.Headers);

            if (user == null)
            {
                // would rather do this inside the GetUserFromToken function, but i don't know how to do that with this framework
                return(Unauthorized());
            }

            bool isBuy;
            IQueryable <StandingOrder> query;

            lock (OrdersController.tradeLock)
            {
                switch (type)
                {
                case "BUY":
                    isBuy = true;
                    query = from o in _context.Orders
                            where (o.isBuy == false) && (o.status == "LIVE") && (o.dollarRate <= limit_price) && (o.user_id != user.id)
                            orderby o.dollarRate ascending
                            select o;
                    break;

                case "SELL":
                    isBuy = false;
                    query = from o in _context.Orders
                            where (o.isBuy == true) && (o.status == "LIVE") && (o.dollarRate >= limit_price) && (o.user_id != user.id)
                            orderby o.dollarRate descending
                            select o;
                    break;

                default:
                    return(BadRequest("type must be `BUY` or `SELL`"));
                }

                var debug = query.ToQueryString();

                if ((isBuy && quantity * limit_price > user.dollars) || (!isBuy && quantity > user.bitcoins))
                {
                    return(BadRequest("Not enough assets on account for this order"));
                }
                long remaining_quantity = quantity;
                while (remaining_quantity > 0)
                {
                    StandingOrder anotherOrder = query.FirstOrDefault();
                    if (anotherOrder == null)
                    {
                        break;
                    }
                    User anotherUser  = _context.Users.Find(anotherOrder.user_id);
                    long amount_trade = Math.Min(anotherOrder.remainingBitcoinAmount, remaining_quantity);

                    remaining_quantity -= amount_trade;
                    long money_trade = amount_trade * anotherOrder.dollarRate;
                    // we trade at the limit of the older standing order (to mimic first doing market order up to limit and then posting a standing order)
                    if (isBuy)
                    {
                        user.bitcoins       += amount_trade;
                        user.dollars        -= money_trade;
                        anotherUser.dollars += money_trade;
                    }
                    else
                    {
                        user.bitcoins        -= amount_trade;
                        user.dollars         += money_trade;
                        anotherUser.bitcoins += amount_trade;
                    }
                    anotherOrder.remainingBitcoinAmount -= amount_trade;
                    if (anotherOrder.remainingBitcoinAmount == 0)
                    {
                        anotherOrder.status = "FULFILLED";
                    }
                    _context.SaveChanges();
                }

                StandingOrder order = order = new StandingOrder(user.id, isBuy, remaining_quantity, quantity, limit_price,
                                                                remaining_quantity == 0 ? "FULFILLED" : "LIVE", DateTime.UtcNow);
                // reserve assets
                if (isBuy)
                {
                    user.dollars -= remaining_quantity * limit_price;
                }
                else
                {
                    user.bitcoins -= remaining_quantity;
                }
                _context.Orders.Add(order);
                _context.SaveChanges();

                return(order);
            }
        }