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); } }
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}"); } } }
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); } }
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); } }