예제 #1
0
        /// <summary>
        /// Calculate overnight swaps for account/instrument/direction order package.
        /// </summary>
        /// <param name="instrument"></param>
        /// <param name="account"></param>
        /// <param name="accountAssetPair"></param>
        /// <param name="direction"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        private async Task ProcessOrders(IReadOnlyList <Order> orders, string instrument, IMarginTradingAccount account,
                                         IAccountAssetPair accountAssetPair, OrderDirection direction)
        {
            //check if swaps had already been taken
            if (_overnightSwapCache.TryGet(OvernightSwapCalculation.GetKey(account.Id, instrument, direction),
                                           out var lastCalc) &&
                lastCalc.Time > CalcLastInvocationTime)
            {
                throw new Exception($"Overnight swaps had already been taken: {JsonConvert.SerializeObject(lastCalc)}");
            }

            //calc swaps
            var swapRate = direction == OrderDirection.Buy ? accountAssetPair.OvernightSwapLong : accountAssetPair.OvernightSwapShort;

            if (swapRate == 0)
            {
                return;
            }

            var total = orders.Sum(order => _commissionService.GetOvernightSwap(order, swapRate));

            if (total == 0)
            {
                return;
            }

            //create calculation obj & add to cache
            var calculation = OvernightSwapCalculation.Create(account.Id, instrument,
                                                              orders.Select(order => order.Id).ToList(), _currentStartTimestamp, true, null, total, swapRate, direction);

            _overnightSwapCache.AddOrReplace(calculation);

            //charge comission
            await _accountManager.UpdateBalanceAsync(
                account : account,
                amount : -total,
                historyType : AccountHistoryType.Swap,
                comment : $"{accountAssetPair.Instrument} {(direction == OrderDirection.Buy ? "long" : "short")} swaps. Positions count: {orders.Count}. Rate: {swapRate}. Time: {_currentStartTimestamp:u}.",
                auditLog : calculation.ToJson());

            //write state and log
            await _overnightSwapStateRepository.AddOrReplaceAsync(calculation);

            await _overnightSwapHistoryRepository.AddAsync(calculation);
        }
예제 #2
0
        /// <summary>
        /// Calculate overnight swaps for account order.
        /// </summary>
        /// <param name="account"></param>
        /// <param name="accountAssetPair"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        private async Task ProcessOrder(Order order, IMarginTradingAccount account,
                                        IAccountAssetPair accountAssetPair)
        {
            //check if swaps had already been taken
            var lastCalcExists = _overnightSwapCache.TryGet(OvernightSwapCalculation.GetKey(order.Id),
                                                            out var lastCalc) &&
                                 lastCalc.Time >= CalcLastInvocationTime();

            if (lastCalcExists)
            {
                await _log.WriteErrorAsync(nameof(OvernightSwapService), nameof(ProcessOrder),
                                           new Exception($"Overnight swap had already been taken, filtering: {JsonConvert.SerializeObject(lastCalc)}"), DateTime.UtcNow);
            }

            //calc swaps
            var swapRate = order.GetOrderType() == OrderDirection.Buy ? accountAssetPair.OvernightSwapLong : accountAssetPair.OvernightSwapShort;

            if (swapRate == 0)
            {
                await _log.WriteInfoAsync(nameof(OvernightSwapService), nameof(ProcessOrder),
                                          $"Overnight swap rate on order {order.Id } is 0, what will not be calculated", DateTime.UtcNow);

                return;
            }

            //special rule for Wednesday
            if (_currentStartTimestamp.DayOfWeek == DayOfWeek.Wednesday)
            {
                swapRate *= 3;
            }

            var total = _commissionService.GetOvernightSwap(order, swapRate);

            if (total == 0)
            {
                await _log.WriteInfoAsync(nameof(OvernightSwapService), nameof(ProcessOrder),
                                          $"Overnight swap rate on order {order.Id } is 0, what will not be calculated", DateTime.UtcNow);

                return;
            }

            //create calculation obj & add to cache
            var volume      = order.Volume;
            var calculation = OvernightSwapCalculation.Create(account.ClientId, account.Id, order.Instrument,
                                                              order.Id, _currentStartTimestamp, true, null, volume, total, swapRate, order.GetOrderType());

            await _accountManager.UpdateBalanceAsync(
                account : account,
                amount : -total,
                historyType : AccountHistoryType.Swap,
                comment : $"Position {order.Id}  swaps. Time: {_currentStartTimestamp:u}.",
                auditLog : calculation.ToJson(),
                eventSourceId : order.Id);

            //update calculation state if previous existed
            var newCalcState = lastCalcExists
                ? OvernightSwapCalculation.Update(calculation, lastCalc)
                : OvernightSwapCalculation.Create(calculation);

            //add to cache
            _overnightSwapCache.AddOrReplace(newCalcState);

            //write state and log
            await _overnightSwapStateRepository.AddOrReplaceAsync(newCalcState);

            await _overnightSwapHistoryRepository.AddAsync(calculation);
        }
예제 #3
0
        /// <summary>
        /// Calculate overnight swaps for account/instrument/direction order package.
        /// </summary>
        /// <param name="instrument"></param>
        /// <param name="account"></param>
        /// <param name="accountAssetPair"></param>
        /// <param name="direction"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        private async Task ProcessOrders(IReadOnlyList <Order> orders, string instrument, IMarginTradingAccount account,
                                         IAccountAssetPair accountAssetPair, OrderDirection direction)
        {
            IReadOnlyList <Order> filteredOrders = orders.ToList();

            //check if swaps had already been taken
            var lastCalcExists = _overnightSwapCache.TryGet(OvernightSwapCalculation.GetKey(account.Id, instrument, direction),
                                                            out var lastCalc) &&
                                 lastCalc.Time >= CalcLastInvocationTime();

            if (lastCalcExists)
            {
                await _log.WriteErrorAsync(nameof(OvernightSwapService), nameof(ProcessOrders),
                                           new Exception($"Overnight swaps had already been taken, filtering: {JsonConvert.SerializeObject(lastCalc)}"), DateTime.UtcNow);

                filteredOrders = orders.Where(x => !lastCalc.OpenOrderIds.Contains(x.Id)).ToList();
            }

            //calc swaps
            var swapRate = direction == OrderDirection.Buy ? accountAssetPair.OvernightSwapLong : accountAssetPair.OvernightSwapShort;

            if (swapRate == 0)
            {
                return;
            }

            var total = filteredOrders.Sum(order => _commissionService.GetOvernightSwap(order, swapRate));

            if (total == 0)
            {
                return;
            }

            //create calculation obj & add to cache
            var volume      = filteredOrders.Select(x => Math.Abs(x.Volume)).Sum();
            var calculation = OvernightSwapCalculation.Create(account.ClientId, account.Id, instrument,
                                                              filteredOrders.Select(order => order.Id).ToList(), _currentStartTimestamp, true, null, volume, total, swapRate, direction);

            //charge comission
            var instrumentName = _assetPairsCache.GetAssetPairByIdOrDefault(accountAssetPair.Instrument)?.Name
                                 ?? accountAssetPair.Instrument;
            await _accountManager.UpdateBalanceAsync(
                account : account,
                amount : -total,
                historyType : AccountHistoryType.Swap,
                comment : $"{instrumentName} {(direction == OrderDirection.Buy ? "long" : "short")} swaps. Volume: {volume}. Positions count: {filteredOrders.Count}. Rate: {swapRate}. Time: {_currentStartTimestamp:u}.",
                auditLog : calculation.ToJson());

            //update calculation state if previous existed
            var newCalcState = lastCalcExists
                                ? OvernightSwapCalculation.Update(calculation, lastCalc)
                                : OvernightSwapCalculation.Create(calculation);

            //add to cache
            _overnightSwapCache.AddOrReplace(newCalcState);

            //write state and log
            await _overnightSwapStateRepository.AddOrReplaceAsync(newCalcState);

            await _overnightSwapHistoryRepository.AddAsync(calculation);
        }