public async Task WriteToErrorLogAsync(CountryKind country, DateTime time, string workerKind, Exception ex) { if (ex == null || string.IsNullOrEmpty(workerKind) || !_canWriteLog) { return; } string fileName = $"{country.GetShortName()}-TT2ErrorLog-{time:yyyyMMdd}.csv"; string filePath = Path.Combine(_logFolderPath, fileName); StringBuilder errorStringBuilder = new StringBuilder(); errorStringBuilder.Append("Exception message = ").AppendLine(ex.Message); errorStringBuilder.Append("Exception stack trace = ").AppendLine(ex.StackTrace); if (ex.InnerException != null) { errorStringBuilder.Append(" Inner exception message = ").AppendLine(ex.InnerException.Message); errorStringBuilder.Append(" Inner exception stack trace = ").AppendLine(ex.InnerException.StackTrace); } string data = $"{time:HH:mm:ss},{workerKind}, {errorStringBuilder}"; await WriteContentToLogAsync(data, filePath).ConfigureAwait(false); }
public async Task WriteToHeartBeatLogAsync(CountryKind country, DateTime time, string workerKind) { if (string.IsNullOrEmpty(workerKind) || !_canWriteLog) { return; } string fileName = $"{country.GetShortName()}-TT2HeartBeat-{time:yyyyMMdd}.csv"; string filePath = Path.Combine(_logFolderPath, fileName); string data = $"{time:HH:mm:ss},{workerKind } sent a heart beat"; await WriteContentToLogAsync(data, filePath).ConfigureAwait(false); }
public bool TryGetItem(CountryKind country, string stockId, out ICurrentPrice item) { string stockFullId = $"{country.GetShortName()}.{stockId}"; if (_storage.TryGetValue(stockFullId, out ICurrentPrice target)) { item = target; return(true); } item = null; return(false); }
public void AddOrUpdateItem(CountryKind country, string stockId, ICurrentPrice item) { string stockFullId = $"{country.GetShortName()}.{stockId}"; if (_storage.ContainsKey(stockFullId) && _storage[stockFullId] == item) { return; } _storage[stockFullId] = item; IsAddedOrUpdated = true; }
public async Task WriteToCurrentPriceLogAsync(CountryKind country, string data) { if (string.IsNullOrEmpty(data) || country == CountryKind.Test || country == CountryKind.Test2 || country == CountryKind.Unknown || !_canWriteLog) { return; } string fileName = $"{country.GetShortName()}-CurrentPrice.csv"; string filePath = Path.Combine(_logFolderPath, fileName); await WriteContentToLogAsync(data, filePath, false).ConfigureAwait(false); }
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 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); } }