Exemple #1
0
        /// <summary>The position of this trade in the order book for the trade type</summary>
        public int OrderBookIndex(ETradeType tt, Unit <decimal> price_q2b, out bool beyond_order_book)
        {
            // Check units
            if (price_q2b < 0m._(RateUnits))
            {
                throw new Exception("Invalid price");
            }

            // If a trade cannot be filled by existing orders, it becomes an offer.
            // E.g.
            //  - Want to trade B2Q == Sell our 'B' to get 'Q'.
            //  - If there are no suitable B2Q.Orders (i.e. people wanting to buy 'B') then our trade becomes an offer in the Q2B order book.
            //    i.e. we want to buy 'Q' so our trade is a Q2B offer.
            var idx = -1;

            switch (tt)
            {
            default: throw new Exception($"Unknown trade type:{tt}");

            case ETradeType.B2Q:
            {
                idx = Q2B.Offers.BinarySearch(x => + x.PriceQ2B.CompareTo(price_q2b), find_insert_position: true);
                beyond_order_book = idx == Q2B.Offers.Count;
                break;
            }

            case ETradeType.Q2B:
            {
                idx = B2Q.Offers.BinarySearch(x => - x.PriceQ2B.CompareTo(price_q2b), find_insert_position: true);
                beyond_order_book = idx == B2Q.Offers.Count;
                break;
            }
            }
            return(idx);
        }
Exemple #2
0
        /// <summary>The total value of orders with a better price than 'price'</summary>
        public Unit <decimal> OrderBookDepth(ETradeType tt, Unit <decimal> price_q2b, out bool beyond_order_book)
        {
            var index  = OrderBookIndex(tt, price_q2b, out beyond_order_book);
            var orders = tt == ETradeType.B2Q ? Q2B.Offers : B2Q.Offers;

            return(orders.Take(index).Sum(x => x.AmountBase));
        }
Exemple #3
0
        /// <summary>Get/Set spot price (in Quote/Base)</summary>
        public Unit <decimal>?this[ETradeType tt]
        {
            get
            {
                return
                    (tt == ETradeType.Q2B ? m_spot_q2b :
                     tt == ETradeType.B2Q ? m_spot_b2q :
                     throw new Exception("Unknown trade type"));
            }
            set
            {
                if (value < 0m._(RateUnits))
                {
                    throw new Exception("Invalid spot price");
                }

                switch (tt)
                {
                default: throw new Exception("Unknown trade type");

                case ETradeType.Q2B: m_spot_q2b = value; break;

                case ETradeType.B2Q: m_spot_b2q = value; break;
                }

                CoinData.NotifyLivePriceChanged(Base);
                CoinData.NotifyLivePriceChanged(Quote);
            }
        }
Exemple #4
0
        // Notes:
        //  - A 'Trade' is a description of a trade that *could* be placed. It is different
        //    to an 'Order' which is live on an exchange, waiting to be filled.
        //  - AmountIn * Price does not have to equal AmountOut, because 'Trade' is used
        //    with the order book to calculate the best price for trading a given amount.
        //    The price will represent the best price that covers all of the amount, not
        //    the spot price.
        //  - Don't implicitly change amounts/prices based on order type for the same reason.
        //    Instead, allow any values to be set and use validate to check they're correct.
        //    The 'EditTradeUI' should be used to modify properties and ensure correct behaviour
        //    w.r.t to order type.
        // Rounding issues:
        //  - Quantisation doesn't help, that just makes the discrepancies larger.
        //  - Instead, maintain separate values for amount in and amount out. These imply the
        //    price and allow control over which side of the trade gets rounded.

        /// <summary>Create a trade on 'pair' to convert 'amount_in' of 'coin_in' to 'amount_out'</summary>
        public Trade(Fund fund, TradePair pair, EOrderType order_type, ETradeType trade_type, Unit <decimal> amount_in, Unit <decimal> amount_out, Unit <decimal>?price_q2b = null, string creator = null)
        {
            // Check trade amounts and units
            if (amount_in < 0m._(trade_type.CoinIn(pair)))
            {
                throw new Exception("Invalid trade 'in' amount");
            }
            if (amount_out < 0m._(trade_type.CoinOut(pair)))
            {
                throw new Exception("Invalid trade 'out' amount");
            }
            if (amount_out != 0 && amount_in != 0 && trade_type.PriceQ2B(amount_out / amount_in) < 0m._(pair.RateUnits))
            {
                throw new Exception("Invalid trade price");
            }

            CreatorName = creator ?? string.Empty;
            Fund        = fund;
            Pair        = pair;
            OrderType   = order_type;
            TradeType   = trade_type;
            AmountIn    = amount_in;
            AmountOut   = amount_out;
            PriceQ2B    =
                price_q2b != null ? price_q2b.Value :
                amount_out != 0 && amount_in != 0 ? TradeType.PriceQ2B(amount_out / amount_in) :
                SpotPriceQ2B;
        }
Exemple #5
0
        /// <summary>Return the order type implied by the given trade type and price relative to the spot price</summary>
        public EOrderType?OrderType(ETradeType trade_type, Unit <decimal> price_q2b)
        {
            // If the spot price is unknown, then so is the impled order type
            var market_price_q2b = SpotPrice[trade_type];

            if (market_price_q2b == null)
            {
                return(null);
            }

            if (trade_type == ETradeType.Q2B)
            {
                return
                    (price_q2b > market_price_q2b.Value * (decimal)(1.0 + SettingsData.Settings.MarketOrderPriceToleranceFrac) ? EOrderType.Stop :
                     price_q2b < market_price_q2b.Value * (decimal)(1.0 - SettingsData.Settings.MarketOrderPriceToleranceFrac) ? EOrderType.Limit :
                     EOrderType.Market);
            }
            if (trade_type == ETradeType.B2Q)
            {
                return
                    (price_q2b <market_price_q2b.Value *(decimal)(1.0 + SettingsData.Settings.MarketOrderPriceToleranceFrac) ? EOrderType.Stop :
                                price_q2b> market_price_q2b.Value * (decimal)(1.0 - SettingsData.Settings.MarketOrderPriceToleranceFrac) ? EOrderType.Limit :
                     EOrderType.Market);
            }
            throw new Exception("Unknown trade type");
        }
Exemple #6
0
 // Notes:
 //   - This is one side of the MarketDepth (either buy or sell).
 //   - The available trades are ordered by price (Increasing for Q2B, Decreasing for B2Q).
 public OrderBook(Coin @base, Coin quote, ETradeType tt)
 {
     TradeType = tt;
     Offers    = new List <Offer>();
     Base      = @base;
     Quote     = quote;
 }
        // Notes:
        //  - A TradeCompleted is a completed single trade that is part of an OrderCompleted
        //  - TradeCompleted doesn't really need 'pair' and 'tt' because they are duplicates
        //    of fields in the containing OrderCompleted. However, they allow convenient conversion
        //    to CoinIn/CoinOut etc.

        public TradeCompleted(long order_id, long trade_id, TradePair pair, ETradeType tt, Unit <decimal> amount_in, Unit <decimal> amount_out, Unit <decimal> commission, Coin commission_coin, DateTimeOffset created, DateTimeOffset updated)
        {
            // Check units

            if (amount_in <= 0m._(tt.CoinIn(pair)))
            {
                throw new Exception("Invalid 'in' amount");
            }
            if (amount_out <= 0m._(tt.CoinOut(pair)))
            {
                throw new Exception("Invalid 'out' amount");
            }
            if (commission < 0m._(commission_coin))
            {
                throw new Exception("Negative commission");
            }
            if (created < Misc.CryptoCurrencyEpoch)
            {
                throw new Exception("Invalid creation time");
            }

            OrderId        = order_id;
            TradeId        = trade_id;
            Pair           = pair;
            TradeType      = tt;
            AmountIn       = amount_in;
            AmountOut      = amount_out;
            Commission     = commission;
            CommissionCoin = commission_coin;
            Created        = created;
            Updated        = updated;
        }
Exemple #8
0
 /// <summary>Return the amount range to validate against for the output currency</summary>
 public RangeF <Unit <decimal> > AmountRangeOut(ETradeType tt)
 {
     return
         (tt == ETradeType.B2Q ? AmountRangeQuote :
          tt == ETradeType.Q2B ? AmountRangeBase :
          throw new Exception("Unknown trade type"));
 }
Exemple #9
0
 /// <summary>Return the unit type for a trade of this type on 'pair'</summary>
 public static string RateUnits(this ETradeType tt, TradePair pair)
 {
     return
         (tt == ETradeType.B2Q ? pair.RateUnits :
          tt == ETradeType.Q2B ? pair.RateUnitsInv :
          throw new Exception("Unknown trade type"));
 }
Exemple #10
0
 /// <summary>Return the opposite trade type</summary>
 public static ETradeType Opposite(this ETradeType tt)
 {
     return
         (tt == ETradeType.Q2B ? ETradeType.B2Q :
          tt == ETradeType.B2Q ? ETradeType.Q2B :
          throw new Exception($"Unknown trade type: {tt}"));
 }
Exemple #11
0
 public static string CoinOut(this ETradeType tt, CoinPair pair)
 {
     return
         (tt == ETradeType.B2Q ? pair.Quote :
          tt == ETradeType.Q2B ? pair.Base :
          throw new Exception("Unknown trade type"));
 }
Exemple #12
0
 /// <summary>Return the 'out' amount for a trade in this trade direction</summary>
 public static Unit <decimal> AmountOut(this ETradeType tt, Unit <decimal> amount_base, Unit <decimal> price_q2b)
 {
     return
         (tt == ETradeType.B2Q ? amount_base * price_q2b :
          tt == ETradeType.Q2B ? amount_base :
          throw new Exception("Unknown trade type"));
 }
Exemple #13
0
 /// <summary>Returns +1 for Q2B, -1 for B2Q</summary>
 public static int Sign(this ETradeType tt)
 {
     return
         (tt == ETradeType.Q2B ? +1 :
          tt == ETradeType.B2Q ? -1 :
          throw new Exception("Unknown trade type"));
 }
Exemple #14
0
 /// <summary>Convert an amount of currency using the available orders. e.g. Q2B => 'amount' in Quote, out in 'Base'</summary>
 public Trade MarketTrade(Fund fund, ETradeType tt, Unit <decimal> amount)
 {
     return
         (tt == ETradeType.Q2B ? QuoteToBase(fund, amount) :
          tt == ETradeType.B2Q ? BaseToQuote(fund, amount) :
          throw new Exception("Unknown trade type"));
 }
Exemple #15
0
    void SetSelectStore(ETradeType tradeType)
    {
        //买
        if (tradeType == ETradeType.ETradeType_Buy)
        {
            m_dicMallItem     = DataManager.Manager <HomeDataManager>().BuyItemDic;
            m_lstHomeTradeTab = DataManager.Manager <HomeDataManager>().GetTabList(m_tradeType);
            m_dicHomeTradeTab = DataManager.Manager <HomeDataManager>().TabNameDic;

            m_label_AddRemove_Text.text = "购买数量:";
            m_label_Obtain_Text.text    = "消    耗:";
            m_label_Btn_name.text       = "购买";
        }

        //卖
        if (tradeType == ETradeType.ETradeType_Sell)
        {
            m_dicMallItem     = DataManager.Manager <HomeDataManager>().SellItemDic;
            m_lstHomeTradeTab = DataManager.Manager <HomeDataManager>().GetTabList(m_tradeType);
            m_dicHomeTradeTab = DataManager.Manager <HomeDataManager>().TabNameDic;

            m_label_AddRemove_Text.text = "出售数量:";
            m_label_Obtain_Text.text    = "获    得:";
            m_label_Btn_name.text       = "出售";
        }

        if (m_GridCreator != null)
        {
            m_GridCreator.ClearAll();                       //清除所有格子
        }
        CreateHomeTradeUI();
    }
Exemple #16
0
        /// <summary>Place an immediate market order</summary>
        public void NewMarketImmediateOrder(Instrument instr, ETradeType trade_type, double?volume = null, double?stop_loss = null, double?take_profit = null)
        {
            // Choose a volume for the position based on the current balance and the stop loss distance
            if (volume == null && stop_loss != null)
            {
                volume = CalculateVolume(instr, stop_loss.Value);
            }
            if (stop_loss == null && volume != null)
            {
                stop_loss = CalculateStopLoss(instr);
            }

            // Create the position we want to hold
            var position = new Position
            {
                SymbolCode  = instr.SymbolCode,
                TradeType   = trade_type,
                EntryTime   = DateTimeOffset.UtcNow.Ticks,
                EntryPrice  = trade_type == ETradeType.Long ? instr.PriceData.BidPrice : instr.PriceData.AskPrice,
                StopLossRel = stop_loss == null ? 0 : 0,                //todo
                Volume      = 0,
                Comment     = "Auto Trade test",
            };

            // Place the order
            Post(new OutMsg.PlaceMarketOrder(position, Settings.Trade.MarketRangePips));
        }
Exemple #17
0
 /// <summary>Return 'price' in (Quote/Base) for this trade direction. Assumes price is in (CoinOut/CoinIn)</summary>
 public static Unit <decimal> PriceQ2B(this ETradeType tt, Unit <decimal> price)
 {
     return
         (price == 0m ? 0m / 1m._(price) :
          tt == ETradeType.B2Q ? price :
          tt == ETradeType.Q2B ? (1m / price) :
          throw new Exception("Unknown trade type"));
 }
Exemple #18
0
        // Notes:
        //  - An OrderCompleted is a completed (or partially completed) Order consisting
        //    of one or more 'TradeCompleted's that where made to complete the order.

        public OrderCompleted(long order_id, Fund fund, TradePair pair, ETradeType tt)
        {
            OrderId   = order_id;
            Fund      = fund;
            TradeType = tt;
            Pair      = pair;
            Trades    = new TradeCompletedCollection(this);
        }
Exemple #19
0
 public Trade(DateTime timeStamp, int quantity, ETradeType tradeType, decimal traderPrice, string tradedStock)
 {
     this.timeStamp = timeStamp;
     this.quantity = quantity;
     this.tradeType = tradeType;
     this.tradePrice = traderPrice;
     this.tradedStock = tradedStock;
 }
Exemple #20
0
        /// <summary>Return the 'base' amount for a trade in this trade direction</summary>
        public static Unit <decimal> AmountBase(this ETradeType tt, Unit <decimal> price_q2b, Unit <decimal>?amount_in = null, Unit <decimal>?amount_out = null)
        {
            var price = (Unit <decimal>?)price_q2b;

            return
                (tt == ETradeType.B2Q ? (amount_in ?? (amount_out / price) ?? throw new Exception("One of 'amount_in' or 'amount_out' must be given")) :
                 tt == ETradeType.Q2B ? (amount_out ?? (amount_in / price) ?? throw new Exception("One of 'amount_in' or 'amount_out' must be given")) :
                 throw new Exception("Unknown trade type"));
        }
Exemple #21
0
        /// <summary>Return the default amount to use for a trade on this pair (in Base currency)</summary>
        public Unit <decimal> DefaultTradeAmountBase(ETradeType tt, Unit <decimal> price_q2b)
        {
            var vol = DefaultTradeAmount(tt);

            return
                (tt == ETradeType.B2Q ? vol :                               // 'vol' is in base
                 tt == ETradeType.Q2B ? vol / price_q2b :                   // 'vol' is in quote
                 throw new Exception("Unknown trade type"));
        }
Exemple #22
0
        public static global::Bittrex.API.EOrderSide ToBittrexTT(this ETradeType trade_type)
        {
            switch (trade_type)
            {
            default: throw new Exception("Unknown trade type");

            case ETradeType.Q2B: return(global::Bittrex.API.EOrderSide.Buy);

            case ETradeType.B2Q: return(global::Bittrex.API.EOrderSide.Sell);
            }
        }
Exemple #23
0
        public static global::Binance.API.EOrderSide ToBinanceTT(this ETradeType trade_type)
        {
            switch (trade_type)
            {
            default: throw new Exception("Unknown trade type");

            case ETradeType.Q2B: return(global::Binance.API.EOrderSide.BUY);

            case ETradeType.B2Q: return(global::Binance.API.EOrderSide.SELL);
            }
        }
Exemple #24
0
        /// <summary>Convert a Tradee trade type to a CAlgo one</summary>
        public static TradeType ToCAlgoTradeType(this ETradeType tt)
        {
            switch (tt)
            {
            default:              throw new Exception("Unknown trade type");

            case ETradeType.None: throw new Exception("Unsupported trade type");

            case ETradeType.Long: return(TradeType.Buy);

            case ETradeType.Short: return(TradeType.Sell);
            }
        }
Exemple #25
0
        // Notes:
        //  - An Order is a request to buy/sell that has been sent to an exchange and
        //    should exist somewhere in their order book. When an Order is filled it
        //    becomes a 'OrderCompleted'

        public Order(long order_id, Fund fund, TradePair pair, EOrderType ot, ETradeType tt, Unit <decimal> amount_in, Unit <decimal> amount_out, Unit <decimal> remaining_in, DateTimeOffset created, DateTimeOffset updated)
            : base(fund, pair, ot, tt, amount_in, amount_out)
        {
            if (created < Misc.CryptoCurrencyEpoch)
            {
                throw new Exception("Invalid creation time");
            }

            OrderId     = order_id;
            UniqueKey   = Guid.NewGuid();
            RemainingIn = remaining_in;
            Created     = created;
            Updated     = updated;
        }
Exemple #26
0
        // Notes:
        // - Represents a single buy or sell order with the broker.
        // - A trade can have more than one of these.
        // - Orders are low level application objects, they don't know about charts, accounts, etc.
        // - Base currency is the currency of the first part of the instrument, e.g GBPNZD - base currency = GBP
        // - Account currency is the currency of the account = base currency * price_data.PipValue / price_data.PipSize

        public Order(int id, Instrument instr, ETradeType trade_type, Trade.EState state)
        {
            Id            = id;
            Instrument    = instr;
            TradeType     = trade_type;
            EntryPrice    = 0;
            ExitPrice     = 0;
            EntryTimeUTC  = DefaultEntryTime;
            ExitTimeUTC   = DefaultExitTime;
            StopLossAbs   = 0;
            TakeProfitAbs = 0;
            Volume        = 0;
            GrossProfit   = 0;
            NetProfit     = 0;
            Commissions   = 0;
            Swap          = 0;
            Comment       = string.Empty;
            State         = state;
        }
Exemple #27
0
        /// <summary>Attempt to make a trade on 'pair' for the given 'price' and base 'amount'</summary>
        private void TryFillOrder(TradePair pair, Fund fund, long order_id, ETradeType tt, EOrderType ot, Unit <decimal> amount_in, Unit <decimal> amount_out, Unit <decimal> remaining_in, out Order ord, out OrderCompleted his)
        {
            // The order can be filled immediately, filled partially, or not filled and remain as an 'Order'.
            // Also, exchanges use the base currency as the amount to fill, so for Q2B trades it's possible
            // that 'amount_in' is less than the trade asked for.
            var market = m_depth[pair];

            // Consume orders
            var price_q2b   = tt.PriceQ2B(amount_out / amount_in);
            var amount_base = tt.AmountBase(price_q2b, amount_in: remaining_in);
            var filled      = market.Consume(pair, tt, ot, price_q2b, amount_base, out var remaining_base);

            // The order is partially or completely filled...
            Debug.Assert(Misc.EqlAmount(amount_base, filled.Sum(x => x.AmountBase) + remaining_base));
            ord = remaining_base != 0 ? new Order(order_id, fund, pair, ot, tt, amount_in, amount_out, tt.AmountIn(remaining_base, price_q2b), Model.UtcNow, Model.UtcNow) : null;
            his = remaining_base != amount_base ? new OrderCompleted(order_id, fund, pair, tt) : null;

            // Add 'TradeCompleted' entries for each order book offer that was filled
            foreach (var fill in filled)
            {
                his.Trades.AddOrUpdate(new TradeCompleted(his.OrderId, ++m_history_id, pair, tt, fill.AmountIn(tt), fill.AmountOut(tt), Exchange.Fee * fill.AmountOut(tt), tt.CoinOut(pair), Model.UtcNow, Model.UtcNow));
            }
        }
Exemple #28
0
 /// <summary>The price that the trade was filled at</summary>
 public Unit <decimal> PriceQ2B(ETradeType tt) => tt.PriceQ2B(AmountOut / AmountIn);
Exemple #29
0
 public void UpdateUI(ResourceList wantedResources, ResourceList bankResources, ResourceList resources, XmlPortList ports, ETradeType tradeType)
 {
     _WantedResources = wantedResources;
     uiWanted.AvailableResources = bankResources;
     _Ports = ports;
     uiOffered.UpdateUI(resources, ports);
     if (tradeType == ETradeType.None)
     {
         pnlAutoTrade.Visibility = Visibility.Collapsed;
         btnCancel.Visibility = Visibility.Visible;
         uiWanted.ReadOnly = false;
     }
     else
     {
         pnlAutoTrade.Visibility = Visibility.Visible;
         btnCancel.Visibility = Visibility.Collapsed;
         lblItemType.Content = Enum.GetName(typeof(ETradeType), tradeType);
         uiWanted.Resources1 = _WantedResources;
         uiWanted.ReadOnly = true;
         switch (tradeType)
         {
             case ETradeType.City: imgItemType.Source = (ImageSource)Core.Instance.Icons["Sea3D"]; break;
             case ETradeType.Town: imgItemType.Source = (ImageSource)Core.Instance.Icons["Town3D"]; break;
             case ETradeType.Road: imgItemType.Source = (ImageSource)Core.Instance.Icons["Road48"]; break;
             case ETradeType.Ship: imgItemType.Source = (ImageSource)Core.Instance.Icons["Ship48"]; break;
             case ETradeType.Devcard: imgItemType.Source = (ImageSource)Core.Instance.Icons["IconBuyDevcard48"]; break;
         }
     }
 }
Exemple #30
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="type">Type</param>
 protected Trade(ETradeType type)
 {
     Type = type;
 }
Exemple #31
0
        /// <summary>Return the default amount to use for a trade on 'pair' (in CoinIn currency)</summary>
        public Unit <decimal> DefaultTradeAmount(ETradeType tt)
        {
            var coin = tt.CoinIn(this);

            return(coin.DefaultTradeAmount);
        }
Exemple #32
0
 /// <summary>The total value of orders with a better price than 'price'</summary>
 public Unit <decimal> OrderBookDepth(ETradeType tt, Unit <decimal> price_q2b, out bool beyond_order_book)
 {
     return(MarketDepth.OrderBookDepth(tt, price_q2b, out beyond_order_book));
 }