private async Task SellNotificationInternalAsync(CountryKind country, IMemberBuyStock memberBuyStock, CancellationToken token)
        {
            if (!BaseData.CurrentPriceStorage.TryGetItem(country, memberBuyStock.StockId, out ICurrentPrice targetItem)
                || targetItem == null
                || !BaseData.CurrentTime.IsSameDay(targetItem.LastTradeTime)
                || token.IsCancellationRequested)
            {
                return;
            }

            string stockFullId = $"{country.GetShortName()}.{memberBuyStock.StockId}";
            decimal? previousMovingAveragePrice = await GetBreakDownComparedPriceAsync(stockFullId, memberBuyStock.Strategy).ConfigureAwait(false);

            if (previousMovingAveragePrice == null || token.IsCancellationRequested)
            {
                return;
            }

            // TODO : refactor
            if (!PriceNotificationChecker.CanNotify(memberBuyStock.MemberEmail,
                                                   stockFullId,
                                                   StockNotificationType.SellStop,
                                                   BaseData.CurrentTime,
                                                   memberBuyStock.Strategy,
                                                   StockBuyState.Sold))
            {
                return;
            }

            // when CurrentPrice < (LowIn10 or StopPrice), notify the member
            string stockName = await GetStockNameAsync(memberBuyStock.StockId).ConfigureAwait(false);
            IEmailTemplate emailTemplate = null;

            if (targetItem.CurrentPrice < (previousMovingAveragePrice.Value - (2 * memberBuyStock.NValue)))
            {
                // lower than previous MA price - 2*N
                emailTemplate = EmailTemplateProvider.GetBreakDownEmailTemplate(memberBuyStock.MemberEmail,
                                                                                stockFullId,
                                                                                stockName,
                                                                                memberBuyStock.Strategy,
                                                                                previousMovingAveragePrice.Value,
                                                                                previousMovingAveragePrice.Value);
            }
            else if (targetItem.CurrentPrice < memberBuyStock.StopPrice)
            {
                // lower than stop price
                emailTemplate = EmailTemplateProvider.GetStopLossEmailTemplate(memberBuyStock.MemberEmail,
                                                                               stockFullId,
                                                                               stockName,
                                                                               memberBuyStock.Strategy,
                                                                               memberBuyStock.StopPrice,
                                                                               memberBuyStock.StopPrice);
            }

            if (emailTemplate == null)
            {
                return;
            }

            if (_testStatus)
            {
                await EmailService.SendEmailAsync(country, BaseData.CurrentTime, emailTemplate).ConfigureAwait(false);
            }
            else
            {
                await EmailService.SendEmailAsync(country, BaseData.CurrentTime, emailTemplate).ConfigureAwait(false);
            }

            PriceNotificationChecker.InsertRecord(memberBuyStock.MemberEmail,
                                                  stockFullId,
                                                  StockNotificationType.SellStop,
                                                  BaseData.CurrentTime,
                                                  memberBuyStock.Strategy,
                                                  StockBuyState.Sold);

            if (_isBackTest)
            {
                await DatabaseOperations.DeleteMemberBuyStockAsync(memberBuyStock.MemberEmail,
                                                                   memberBuyStock.Country,
                                                                   memberBuyStock.StockId).ConfigureAwait(false);
            }
        }
Exemplo n.º 2
0
        private async Task AddBuyAsync(CancellationToken token)
        {
            // get MemberBuyStock from database
            IMemberBuyStock memberBuyStock = (await DatabaseOperations.GetMemberBuyStocksAsync(_memberStock.MemberEmail).ConfigureAwait(false))?
                                             .FirstOrDefault(a => (a.State != StockBuyState.Sold || a.State != StockBuyState.Unknown) &&
                                                             string.Equals(a.MemberEmail, _memberStock.MemberEmail, StringComparison.OrdinalIgnoreCase) &&
                                                             a.Country == _memberStock.Country &&
                                                             string.Equals(a.StockId, _memberStock.StockId, StringComparison.OrdinalIgnoreCase));

            if (memberBuyStock == null)
            {
                return;
            }

            string  stockFullId    = $"{memberBuyStock.Country.GetShortName()}.{memberBuyStock.StockId}";
            decimal buyPrice       = memberBuyStock.BuyPrice;
            decimal nValue         = memberBuyStock.NValue;
            decimal firstAddPrice  = buyPrice + nValue;
            decimal secondAddPrice = firstAddPrice + nValue;
            decimal thirdAddPrie   = secondAddPrice + nValue;
            decimal fourthAddPrice = thirdAddPrie + nValue;

            if (!BaseData.CurrentPriceStorage.TryGetItem(memberBuyStock.Country, memberBuyStock.StockId, out ICurrentPrice target) ||
                target == null ||
                !BaseData.CurrentTime.IsSameDay(target.LastTradeTime))
            {
                return;
            }

            decimal        currentPrice  = target.CurrentPrice;
            IEmailTemplate emailTemplate = null;
            StockBuyState  newBuyState   = StockBuyState.Unknown;
            string         stockName     = await GetStockNameAsync(stockFullId).ConfigureAwait(false);

            if (token.IsCancellationRequested)
            {
                return;
            }

            // TODO : refactor
            if (firstAddPrice <= currentPrice &&
                currentPrice < secondAddPrice &&
                memberBuyStock.State == StockBuyState.Buy)
            {
                newBuyState = StockBuyState.FirstAdd;
                decimal newStopPrice = firstAddPrice - (nValue * 2);
                await DatabaseOperations.UpdateMemberBuyStockAsync(memberBuyStock.MemberEmail, memberBuyStock.Country, memberBuyStock.StockId, newStopPrice, newBuyState).ConfigureAwait(false);

                emailTemplate = EmailTemplateProvider.GetAddOnBuyEmailTemplate(memberBuyStock.MemberEmail, memberBuyStock.StockId, stockName, newStopPrice, newBuyState);
            }
            else if (secondAddPrice <= currentPrice &&
                     currentPrice < thirdAddPrie &&
                     memberBuyStock.State.GetStockBuyStateValue() <= 1)
            {
                newBuyState = StockBuyState.SecondAdd;
                decimal newStopPrice = secondAddPrice - (nValue * 2);
                await DatabaseOperations.UpdateMemberBuyStockAsync(memberBuyStock.MemberEmail, memberBuyStock.Country, memberBuyStock.StockId, newStopPrice, newBuyState).ConfigureAwait(false);

                emailTemplate = EmailTemplateProvider.GetAddOnBuyEmailTemplate(memberBuyStock.MemberEmail, memberBuyStock.StockId, stockName, newStopPrice, newBuyState);
            }
            else if (thirdAddPrie <= currentPrice &&
                     currentPrice < fourthAddPrice &&
                     memberBuyStock.State.GetStockBuyStateValue() <= 2)
            {
                newBuyState = StockBuyState.ThirdAdd;
                decimal newStopPrice = thirdAddPrie - (nValue * 2);
                await DatabaseOperations.UpdateMemberBuyStockAsync(memberBuyStock.MemberEmail, memberBuyStock.Country, memberBuyStock.StockId, newStopPrice, newBuyState).ConfigureAwait(false);

                emailTemplate = EmailTemplateProvider.GetAddOnBuyEmailTemplate(memberBuyStock.MemberEmail, memberBuyStock.StockId, stockName, newStopPrice, newBuyState);
            }
            else if (fourthAddPrice <= currentPrice &&
                     memberBuyStock.State.GetStockBuyStateValue() <= 3)
            {
                newBuyState = StockBuyState.FourthAdd;
                decimal newStopPrice = fourthAddPrice - (nValue * 2);
                await DatabaseOperations.UpdateMemberBuyStockAsync(memberBuyStock.MemberEmail, memberBuyStock.Country, memberBuyStock.StockId, newStopPrice, newBuyState).ConfigureAwait(false);

                emailTemplate = EmailTemplateProvider.GetAddOnBuyEmailTemplate(memberBuyStock.MemberEmail, memberBuyStock.StockId, stockName, newStopPrice, newBuyState);
            }

            if (emailTemplate != null &&
                PriceNotificationChecker.CanNotify(memberBuyStock.MemberEmail,
                                                   stockFullId,
                                                   StockNotificationType.Buy,
                                                   BaseData.CurrentTime,
                                                   memberBuyStock.Strategy,
                                                   newBuyState))
            {
                if (_testStatus)
                {
                    await EmailService.SendEmailAsync(BaseData.Country, BaseData.CurrentTime, emailTemplate).ConfigureAwait(false);
                }
                else
                {
                    await EmailService.SendEmailAsync(BaseData.Country, BaseData.CurrentTime, emailTemplate).ConfigureAwait(false);
                }

                PriceNotificationChecker.InsertRecord(memberBuyStock.MemberEmail, stockFullId, StockNotificationType.Buy, BaseData.CurrentTime, memberBuyStock.Strategy, newBuyState);

                if (!_testStatus)
                {
                    Task t = BaseData.GetLogger().WriteToWorkerLogAsync(BaseData.Country, BaseData.CurrentTime, "TurtleBuyStrategy", $"{memberBuyStock.Strategy}, add buy ({stockFullId}) email is sent to {emailTemplate.ReceipentEmail} and new state is {newBuyState}");
                }
            }
        }
Exemplo n.º 3
0
        private async Task MovingAverageBuyInternalAsync(CountryKind country, IMemberStock memberStock, ICurrentPriceStorage storage)
        {
            string stockFullId = $"{country.GetShortName()}.{memberStock.StockId}";

            if (!storage.TryGetItem(country, memberStock.StockId, out ICurrentPrice target) ||
                target == null ||
                !BaseData.CurrentTime.IsSameDay(target.LastTradeTime))
            {
                return;
            }

            decimal todayHigh = target.TodayHighPrice;
            decimal?previousMovingAveragePrice = await GetBreakThroughComparedPriceAsync(stockFullId, memberStock.Strategy).ConfigureAwait(false);

            if (!previousMovingAveragePrice.HasValue || previousMovingAveragePrice.Value >= todayHigh)
            {
                return;
            }

            bool isUserHoldStock = await IfUserHoldStock(memberStock.MemberEmail, stockFullId).ConfigureAwait(false);

            if (isUserHoldStock)
            {
                return;
            }

            // TODO : refactor
            // check if notify today
            if (!PriceNotificationChecker.CanNotify(memberStock.MemberEmail,
                                                    stockFullId,
                                                    StockNotificationType.Buy,
                                                    BaseData.CurrentTime,
                                                    memberStock.Strategy,
                                                    StockBuyState.Buy))
            {
                return;
            }

            string stockName = await GetStockNameAsync(stockFullId).ConfigureAwait(false);

            // should change to some EmailTemplateProvider
            IEmailTemplate emailMessage = EmailTemplateProvider.GetBreakThroughEmailTemplate(memberStock.MemberEmail,
                                                                                             stockFullId,
                                                                                             stockName,
                                                                                             memberStock.Strategy,
                                                                                             todayHigh,
                                                                                             previousMovingAveragePrice.HasValue ? previousMovingAveragePrice.Value : -1);

            if (_testStatus)
            {
                await EmailService.SendEmailAsync(country, BaseData.CurrentTime, emailMessage).ConfigureAwait(false);
            }
            else
            {
                await EmailService.SendEmailAsync(country, BaseData.CurrentTime, emailMessage).ConfigureAwait(false);
            }


            PriceNotificationChecker.InsertRecord(memberStock.MemberEmail, stockFullId, StockNotificationType.Buy, BaseData.CurrentTime, memberStock.Strategy, StockBuyState.Buy);

            if (!_testStatus)
            {
                _ = BaseData.GetLogger().WriteToWorkerLogAsync(country, BaseData.CurrentTime, "MovingAverageBuyStrategy", $"{memberStock.Strategy}, first buy ({stockFullId}) email is sent to {memberStock.MemberEmail}");
            }

            if (_isBackTest)
            {
                //await BackTestFirstBuyOperationAsync(previousHighBoundPrice.Value);
            }
        }
Exemplo n.º 4
0
        private async Task FirstBuyInternalAsync(IMemberStock memberStock, ICurrentPriceStorage priceStorage)
        {
            if (!priceStorage.TryGetItem(memberStock.Country, memberStock.StockId, out ICurrentPrice target) ||
                target == null ||
                !BaseData.CurrentTime.IsSameDay(target.LastTradeTime))
            {
                return;
            }

            decimal todayHigh              = target.TodayHighPrice;
            string  stockFullId            = $"{memberStock.Country.GetShortName()}.{memberStock.StockId}";
            decimal?previousHighBoundPrice = await GetBreakThroughComparedPriceAsync(stockFullId, memberStock.Strategy).ConfigureAwait(false);

            // check if breaks through high price in N system
            if (!previousHighBoundPrice.HasValue || previousHighBoundPrice.Value >= todayHigh)
            {
                return;
            }

            // check if this member bought the stock. if bought, no notification.
            bool isUserHold = await IfUserHoldStock(_memberStock.MemberEmail, stockFullId).ConfigureAwait(false);

            if (isUserHold)
            {
                return;
            }

            // check if notify today
            if (!PriceNotificationChecker.CanNotify(_memberStock.MemberEmail,
                                                    stockFullId,
                                                    StockNotificationType.Buy,
                                                    BaseData.CurrentTime,
                                                    _memberStock.Strategy,
                                                    StockBuyState.Buy))
            {
                return;
            }

            string stockName = await GetStockNameAsync(stockFullId).ConfigureAwait(false);

            // should change to some EmailTemplateProvider
            IEmailTemplate emailMessage = EmailTemplateProvider.GetBreakThroughEmailTemplate(_memberStock.MemberEmail,
                                                                                             stockFullId,
                                                                                             stockName,
                                                                                             _memberStock.Strategy,
                                                                                             todayHigh,
                                                                                             previousHighBoundPrice ?? -1);

            if (_testStatus)
            {
                _ = EmailService.SendEmailAsync(BaseData.Country, BaseData.CurrentTime, emailMessage).ConfigureAwait(false);
            }
            else
            {
                _ = EmailService.SendEmailAsync(BaseData.Country, BaseData.CurrentTime, emailMessage).ConfigureAwait(false);
            }

            PriceNotificationChecker.InsertRecord(_memberStock.MemberEmail,
                                                  stockFullId,
                                                  StockNotificationType.Buy,
                                                  BaseData.CurrentTime,
                                                  _memberStock.Strategy,
                                                  StockBuyState.Buy);

            if (!_testStatus)
            {
                _ = BaseData.GetLogger().WriteToWorkerLogAsync(BaseData.Country,
                                                               BaseData.CurrentTime,
                                                               "TurtleBuyStrategy",
                                                               $"{_memberStock.Strategy}, first buy ({stockFullId}) email is sent to {_memberStock.MemberEmail}").ConfigureAwait(false);
            }

            if (_isBackTest)
            {
                await BackTestFirstBuyOperationAsync(previousHighBoundPrice.Value).ConfigureAwait(false);
            }
        }