Optimize GetGainLossWithDetailByDateAnd Account GetGainLossWithDetailByDate
Some checks failed
Build .NET Project / build (push) Has been cancelled
Some checks failed
Build .NET Project / build (push) Has been cancelled
This commit is contained in:
@@ -125,54 +125,68 @@ namespace MarketDataServer.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GetGainLossWithDetailByDate - Optimizing calls to DA methods
|
/// GetGainLossWithDetailByDate2 - Refactored: cache primed once before loop.
|
||||||
|
/// GenerateGainLoss still called per symbol (GainLossCollection is a time series,
|
||||||
|
/// not keyed by symbol) but cache is already populated so DB fetches are skipped.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <param name="selectedDate"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IEnumerable<GainLossSummaryItemDetail> GetGainLossWithDetailByDate(String token,DateTime selectedDate)
|
public IEnumerable<GainLossSummaryItemDetail> GetGainLossWithDetailByDate(String token, DateTime selectedDate)
|
||||||
{
|
{
|
||||||
Profiler profiler = new Profiler();
|
Profiler profiler = new Profiler();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG,$"Start");
|
MDTrace.WriteLine(LogLevel.DEBUG, $"Start");
|
||||||
if (!Authorizations.GetInstance().IsAuthorized(token)) return null;
|
if (!Authorizations.GetInstance().IsAuthorized(token)) return null;
|
||||||
GLPriceCache.GetInstance().Refresh();
|
|
||||||
PortfolioTrades portfolioTrades = PortfolioDA.GetTrades();
|
PortfolioTrades portfolioTrades = PortfolioDA.GetTrades();
|
||||||
PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate);
|
PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate);
|
||||||
|
|
||||||
|
// Prime cache once for all symbols before any calculation begins.
|
||||||
|
// Guarantees all symbols are cached and open positions have the latest intraday price.
|
||||||
|
// GenerateGainLoss calls Add(PortfolioTrades) internally per symbol — those calls
|
||||||
|
// will hit the cache and skip DB fetches since all symbols are already populated.
|
||||||
|
GLPriceCache.GetInstance().Add(tradesOnOrBefore);
|
||||||
GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate);
|
GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate);
|
||||||
List<String> symbols = gainLossSummaryItems.Select(x => x.Symbol).ToList();
|
List<String> symbols = gainLossSummaryItems.Select(x => x.Symbol).ToList();
|
||||||
Dictionary<String,DateTime> latestDates = PricingDA.GetLatestDates(symbols);
|
Dictionary<String, DateTime> latestDates = PricingDA.GetLatestDates(symbols);
|
||||||
|
if (null == gainLossGenerator) gainLossGenerator = new ActiveGainLossGenerator();
|
||||||
List<GainLossSummaryItemDetail> gainLossSummaryItemDetailCollection = new List<GainLossSummaryItemDetail>();
|
List<GainLossSummaryItemDetail> gainLossSummaryItemDetailCollection = new List<GainLossSummaryItemDetail>();
|
||||||
foreach (GainLossSummaryItem gainLossSummaryItem in gainLossSummaryItems)
|
foreach (GainLossSummaryItem gainLossSummaryItem in gainLossSummaryItems)
|
||||||
{
|
{
|
||||||
GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem);
|
GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem);
|
||||||
portfolioTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol);
|
|
||||||
double weightAdjustedDividendYield = portfolioTrades.GetWeightAdjustedDividendYield();
|
PortfolioTrades symbolTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol);
|
||||||
|
if (null == symbolTrades || 0 == symbolTrades.Count) continue;
|
||||||
|
|
||||||
|
double weightAdjustedDividendYield = symbolTrades.GetWeightAdjustedDividendYield();
|
||||||
DateTime currentDate = latestDates[gainLossSummaryItem.Symbol];
|
DateTime currentDate = latestDates[gainLossSummaryItem.Symbol];
|
||||||
if (null == portfolioTrades || 0 == portfolioTrades.Count) continue;
|
double shares = symbolTrades.Sum(x => x.Shares);
|
||||||
double shares = (from PortfolioTrade portfolioTrade in portfolioTrades select portfolioTrade.Shares).Sum();
|
double exposure = symbolTrades.Sum(x => x.Exposure());
|
||||||
double exposure = portfolioTrades.Sum(x => x.Exposure());
|
|
||||||
if(null==gainLossGenerator) gainLossGenerator=new ActiveGainLossGenerator();
|
// GainLossCollection is a date-based time series — must be called per symbol
|
||||||
GainLossCollection gainLoss=gainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions
|
// Cache is already primed so internal Add(PortfolioTrades) skips DB fetches
|
||||||
|
GainLossCollection gainLoss = gainLossGenerator.GenerateGainLoss(symbolTrades);
|
||||||
GainLossItem gainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault();
|
GainLossItem gainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault();
|
||||||
gainLossSummaryItemDetail.Lots = portfolioTrades.Count;
|
|
||||||
|
gainLossSummaryItemDetail.Lots = symbolTrades.Count;
|
||||||
gainLossSummaryItemDetail.Shares = shares;
|
gainLossSummaryItemDetail.Shares = shares;
|
||||||
gainLossSummaryItemDetail.Exposure = exposure;
|
gainLossSummaryItemDetail.Exposure = exposure;
|
||||||
|
|
||||||
if (!double.IsNaN(weightAdjustedDividendYield))
|
if (!double.IsNaN(weightAdjustedDividendYield))
|
||||||
{
|
{
|
||||||
gainLossSummaryItemDetail.DividendYield = weightAdjustedDividendYield;
|
gainLossSummaryItemDetail.DividendYield = weightAdjustedDividendYield;
|
||||||
gainLossSummaryItemDetail.AnnualDividend = exposure * weightAdjustedDividendYield;
|
gainLossSummaryItemDetail.AnnualDividend = exposure * weightAdjustedDividendYield;
|
||||||
}
|
}
|
||||||
Prices prices = GLPriceCache.GetInstance().GetPrices(gainLossSummaryItem.Symbol, currentDate, 3); // cache should be refreshed after GainLossSummaryItemCollection
|
// Cache is already primed — pure memory read
|
||||||
Price p1 = prices.Count>0?prices[0]:default;
|
Prices prices = GLPriceCache.GetInstance().GetPrices(gainLossSummaryItem.Symbol, currentDate, 3);
|
||||||
Price p2 = prices.Count>1?prices[1]:default;
|
Price p1 = prices.Count > 0 ? prices[0] : default;
|
||||||
PortfolioTrades symbolTrades = new PortfolioTrades(portfolioTrades.Where(x=>x.Symbol.Equals(gainLossSummaryItem.Symbol)).ToList());
|
Price p2 = prices.Count > 1 ? prices[1] : default;
|
||||||
ParityElement parityElement = ParityGenerator.GenerateBreakEven(symbolTrades, p1);
|
|
||||||
|
PortfolioTrades tradesForSymbol = new PortfolioTrades(symbolTrades.Where(x => x.Symbol.Equals(gainLossSummaryItem.Symbol)).ToList());
|
||||||
|
ParityElement parityElement = ParityGenerator.GenerateBreakEven(tradesForSymbol, p1);
|
||||||
gainLossSummaryItemDetail.ParityElement = parityElement;
|
gainLossSummaryItemDetail.ParityElement = parityElement;
|
||||||
if (null != parityElement)
|
|
||||||
|
if (null != parityElement && null != gainLossItem)
|
||||||
{
|
{
|
||||||
gainLossSummaryItemDetail.AllTimeGainLossPercent = gainLossItem.GainLossPercent;
|
gainLossSummaryItemDetail.AllTimeGainLossPercent = gainLossItem.GainLossPercent;
|
||||||
gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent = parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100);
|
gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent = parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100);
|
||||||
@@ -185,11 +199,11 @@ namespace MarketDataServer.Controllers
|
|||||||
}
|
}
|
||||||
gainLossSummaryItemDetailCollection.Add(gainLossSummaryItemDetail);
|
gainLossSummaryItemDetailCollection.Add(gainLossSummaryItemDetail);
|
||||||
}
|
}
|
||||||
|
|
||||||
// **** Add an aggregate entry
|
// **** Add an aggregate entry
|
||||||
GainLossSummaryItemDetail gainLossSummaryTotals = new GainLossSummaryItemDetail();
|
GainLossSummaryItemDetail gainLossSummaryTotals = new GainLossSummaryItemDetail();
|
||||||
gainLossSummaryTotals.Symbol = "";
|
gainLossSummaryTotals.Symbol = "";
|
||||||
gainLossSummaryTotals.CompanyName = "Account Summary";
|
gainLossSummaryTotals.CompanyName = "Account Summary";
|
||||||
|
|
||||||
if (null != gainLossSummaryItemDetailCollection && gainLossSummaryItemDetailCollection.Count > 0)
|
if (null != gainLossSummaryItemDetailCollection && gainLossSummaryItemDetailCollection.Count > 0)
|
||||||
{
|
{
|
||||||
gainLossSummaryTotals.Date = gainLossSummaryItemDetailCollection.Min(x => x.Date);
|
gainLossSummaryTotals.Date = gainLossSummaryItemDetailCollection.Min(x => x.Date);
|
||||||
@@ -215,71 +229,195 @@ namespace MarketDataServer.Controllers
|
|||||||
// ****
|
// ****
|
||||||
return gainLossSummaryItemDetailCollection;
|
return gainLossSummaryItemDetailCollection;
|
||||||
}
|
}
|
||||||
catch(Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}");
|
MDTrace.WriteLine(LogLevel.DEBUG, $"Exception:{exception.ToString()}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)");
|
MDTrace.WriteLine(LogLevel.DEBUG, $"Done, total took {profiler.End()} (ms)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /// <summary>
|
||||||
|
// /// GetGainLossWithDetailByDate - Optimizing calls to DA methods
|
||||||
|
// /// </summary>
|
||||||
|
// /// <param name="token"></param>
|
||||||
|
// /// <param name="selectedDate"></param>
|
||||||
|
// /// <returns></returns>
|
||||||
|
// [HttpGet]
|
||||||
|
// public IEnumerable<GainLossSummaryItemDetail> GetGainLossWithDetailByDate1(String token,DateTime selectedDate)
|
||||||
|
// {
|
||||||
|
// Profiler profiler = new Profiler();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// MDTrace.WriteLine(LogLevel.DEBUG,$"Start");
|
||||||
|
// if (!Authorizations.GetInstance().IsAuthorized(token)) return null;
|
||||||
|
// GLPriceCache.GetInstance().Refresh();
|
||||||
|
// PortfolioTrades portfolioTrades = PortfolioDA.GetTrades();
|
||||||
|
// PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate);
|
||||||
|
// GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate);
|
||||||
|
// List<String> symbols = gainLossSummaryItems.Select(x => x.Symbol).ToList();
|
||||||
|
// Dictionary<String,DateTime> latestDates = PricingDA.GetLatestDates(symbols);
|
||||||
|
|
||||||
|
// List<GainLossSummaryItemDetail> gainLossSummaryItemDetailCollection = new List<GainLossSummaryItemDetail>();
|
||||||
|
// foreach (GainLossSummaryItem gainLossSummaryItem in gainLossSummaryItems)
|
||||||
|
// {
|
||||||
|
// GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem);
|
||||||
|
// portfolioTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol);
|
||||||
|
// double weightAdjustedDividendYield = portfolioTrades.GetWeightAdjustedDividendYield();
|
||||||
|
// DateTime currentDate = latestDates[gainLossSummaryItem.Symbol];
|
||||||
|
// if (null == portfolioTrades || 0 == portfolioTrades.Count) continue;
|
||||||
|
// double shares = (from PortfolioTrade portfolioTrade in portfolioTrades select portfolioTrade.Shares).Sum();
|
||||||
|
// double exposure = portfolioTrades.Sum(x => x.Exposure());
|
||||||
|
// if(null==gainLossGenerator) gainLossGenerator=new ActiveGainLossGenerator();
|
||||||
|
// GainLossCollection gainLoss=gainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions
|
||||||
|
// GainLossItem gainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault();
|
||||||
|
// gainLossSummaryItemDetail.Lots = portfolioTrades.Count;
|
||||||
|
// gainLossSummaryItemDetail.Shares = shares;
|
||||||
|
// gainLossSummaryItemDetail.Exposure = exposure;
|
||||||
|
// if (!double.IsNaN(weightAdjustedDividendYield))
|
||||||
|
// {
|
||||||
|
// gainLossSummaryItemDetail.DividendYield = weightAdjustedDividendYield;
|
||||||
|
// gainLossSummaryItemDetail.AnnualDividend = exposure * weightAdjustedDividendYield;
|
||||||
|
// }
|
||||||
|
// Prices prices = GLPriceCache.GetInstance().GetPrices(gainLossSummaryItem.Symbol, currentDate, 3); // cache should be refreshed after GainLossSummaryItemCollection
|
||||||
|
// Price p1 = prices.Count>0?prices[0]:default;
|
||||||
|
// Price p2 = prices.Count>1?prices[1]:default;
|
||||||
|
// PortfolioTrades symbolTrades = new PortfolioTrades(portfolioTrades.Where(x=>x.Symbol.Equals(gainLossSummaryItem.Symbol)).ToList());
|
||||||
|
// ParityElement parityElement = ParityGenerator.GenerateBreakEven(symbolTrades, p1);
|
||||||
|
// gainLossSummaryItemDetail.ParityElement = parityElement;
|
||||||
|
// if (null != parityElement)
|
||||||
|
// {
|
||||||
|
// gainLossSummaryItemDetail.AllTimeGainLossPercent = gainLossItem.GainLossPercent;
|
||||||
|
// gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent = parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100);
|
||||||
|
// }
|
||||||
|
// if (null != p1 && null != p2)
|
||||||
|
// {
|
||||||
|
// double change = (p1.Close - p2.Close) / p2.Close;
|
||||||
|
// gainLossSummaryItemDetail.LatestPrice = p1;
|
||||||
|
// gainLossSummaryItemDetail.PriceChange = change;
|
||||||
|
// }
|
||||||
|
// gainLossSummaryItemDetailCollection.Add(gainLossSummaryItemDetail);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // **** Add an aggregate entry
|
||||||
|
// GainLossSummaryItemDetail gainLossSummaryTotals = new GainLossSummaryItemDetail();
|
||||||
|
// gainLossSummaryTotals.Symbol = "";
|
||||||
|
// gainLossSummaryTotals.CompanyName = "Account Summary";
|
||||||
|
// if (null != gainLossSummaryItemDetailCollection && gainLossSummaryItemDetailCollection.Count > 0)
|
||||||
|
// {
|
||||||
|
// gainLossSummaryTotals.Date = gainLossSummaryItemDetailCollection.Min(x => x.Date);
|
||||||
|
// gainLossSummaryTotals.Exposure = gainLossSummaryItemDetailCollection.Sum(x => x.Exposure);
|
||||||
|
// gainLossSummaryTotals.Change = gainLossSummaryItemDetailCollection.Sum(x => x.Change);
|
||||||
|
// gainLossSummaryTotals.CurrentGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.CurrentGainLoss);
|
||||||
|
// gainLossSummaryTotals.PreviousGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.PreviousGainLoss);
|
||||||
|
// gainLossSummaryTotals.ChangePercent = ((gainLossSummaryTotals.CurrentGainLoss - gainLossSummaryTotals.PreviousGainLoss) / Math.Abs(gainLossSummaryTotals.PreviousGainLoss)) * 100.00;
|
||||||
|
// gainLossSummaryTotals.LatestPrice = new Price();
|
||||||
|
// gainLossSummaryTotals.PriceChange = 0;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// gainLossSummaryTotals.Date = selectedDate;
|
||||||
|
// gainLossSummaryTotals.Change = 0.00;
|
||||||
|
// gainLossSummaryTotals.CurrentGainLoss = 0.00;
|
||||||
|
// gainLossSummaryTotals.PreviousGainLoss = 0.00;
|
||||||
|
// gainLossSummaryTotals.ChangePercent = 0.00;
|
||||||
|
// gainLossSummaryTotals.LatestPrice = new Price();
|
||||||
|
// gainLossSummaryTotals.PriceChange = 0;
|
||||||
|
// }
|
||||||
|
// gainLossSummaryItemDetailCollection.Insert(0, gainLossSummaryTotals);
|
||||||
|
// // ****
|
||||||
|
// return gainLossSummaryItemDetailCollection;
|
||||||
|
// }
|
||||||
|
// catch(Exception exception)
|
||||||
|
// {
|
||||||
|
// MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}");
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// finally
|
||||||
|
// {
|
||||||
|
// MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IEnumerable<GainLossSummaryItemDetail> GetGainLossWithDetailByDateAndAccount(String token, DateTime selectedDate, String account)
|
public IEnumerable<GainLossSummaryItemDetail> GetGainLossWithDetailByDateAndAccount(String token, DateTime selectedDate, String account)
|
||||||
{
|
{
|
||||||
Profiler profiler = new Profiler();
|
Profiler profiler = new Profiler();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG,$"Start");
|
MDTrace.WriteLine(LogLevel.DEBUG, $"Start");
|
||||||
if (!Authorizations.GetInstance().IsAuthorized(token)) return null;
|
if (!Authorizations.GetInstance().IsAuthorized(token)) return null;
|
||||||
GLPriceCache.GetInstance().Refresh();
|
|
||||||
PortfolioTrades portfolioTrades = PortfolioDA.GetTrades();
|
PortfolioTrades portfolioTrades = PortfolioDA.GetTrades();
|
||||||
portfolioTrades = new PortfolioTrades(portfolioTrades.Where(x => x.Account.Equals(account)).ToList());
|
portfolioTrades = new PortfolioTrades(portfolioTrades.Where(x => x.Account.Equals(account)).ToList());
|
||||||
PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate);
|
PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate);
|
||||||
|
|
||||||
|
// Prime cache once for all symbols before any calculation begins.
|
||||||
|
// Guarantees all symbols are cached and open positions have the latest intraday price.
|
||||||
|
// GenerateGainLoss calls Add(PortfolioTrades) internally per symbol those calls
|
||||||
|
// will hit the cache and skip DB fetches since all symbols are already populated.
|
||||||
|
GLPriceCache.GetInstance().Add(tradesOnOrBefore);
|
||||||
|
|
||||||
GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate);
|
GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate);
|
||||||
List<String> symbols = gainLossSummaryItems.Select(x => x.Symbol).ToList();
|
List<String> symbols = gainLossSummaryItems.Select(x => x.Symbol).ToList();
|
||||||
Dictionary<String,DateTime> latestDates = PricingDA.GetLatestDates(symbols);
|
Dictionary<String, DateTime> latestDates = PricingDA.GetLatestDates(symbols);
|
||||||
|
|
||||||
List<GainLossSummaryItemDetail> gainLossSummaryItemDetailCollection=new List<GainLossSummaryItemDetail>();
|
if (null == gainLossGenerator) gainLossGenerator = new ActiveGainLossGenerator();
|
||||||
foreach(GainLossSummaryItem gainLossSummaryItem in gainLossSummaryItems)
|
|
||||||
|
List<GainLossSummaryItemDetail> gainLossSummaryItemDetailCollection = new List<GainLossSummaryItemDetail>();
|
||||||
|
|
||||||
|
foreach (GainLossSummaryItem gainLossSummaryItem in gainLossSummaryItems)
|
||||||
{
|
{
|
||||||
GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem);
|
GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem);
|
||||||
portfolioTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol);
|
|
||||||
double weightAdjustedDividendYield = portfolioTrades.GetWeightAdjustedDividendYield();
|
PortfolioTrades symbolTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol);
|
||||||
|
if (null == symbolTrades || 0 == symbolTrades.Count) continue;
|
||||||
|
|
||||||
|
double weightAdjustedDividendYield = symbolTrades.GetWeightAdjustedDividendYield();
|
||||||
DateTime currentDate = latestDates[gainLossSummaryItem.Symbol];
|
DateTime currentDate = latestDates[gainLossSummaryItem.Symbol];
|
||||||
if(null==portfolioTrades||0==portfolioTrades.Count)continue;
|
double shares = symbolTrades.Sum(x => x.Shares);
|
||||||
double shares = (from PortfolioTrade portfolioTrade in portfolioTrades select portfolioTrade.Shares).Sum();
|
double exposure = symbolTrades.Sum(x => x.Exposure());
|
||||||
double exposure = portfolioTrades.Sum(x => x.Exposure());
|
|
||||||
if(null==gainLossGenerator) gainLossGenerator=new ActiveGainLossGenerator();
|
// GainLossCollection is a date-based time series must be called per symbol
|
||||||
GainLossCollection gainLoss = gainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions
|
// Cache is already primed so internal Add(PortfolioTrades) skips DB fetches
|
||||||
|
GainLossCollection gainLoss = gainLossGenerator.GenerateGainLoss(symbolTrades);
|
||||||
GainLossItem gainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault();
|
GainLossItem gainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault();
|
||||||
gainLossSummaryItemDetail.Lots=portfolioTrades.Count;
|
|
||||||
gainLossSummaryItemDetail.Shares=shares;
|
gainLossSummaryItemDetail.Lots = symbolTrades.Count;
|
||||||
gainLossSummaryItemDetail.Exposure=exposure;
|
gainLossSummaryItemDetail.Shares = shares;
|
||||||
|
gainLossSummaryItemDetail.Exposure = exposure;
|
||||||
|
|
||||||
if (!double.IsNaN(weightAdjustedDividendYield))
|
if (!double.IsNaN(weightAdjustedDividendYield))
|
||||||
{
|
{
|
||||||
gainLossSummaryItemDetail.DividendYield=weightAdjustedDividendYield;
|
gainLossSummaryItemDetail.DividendYield = weightAdjustedDividendYield;
|
||||||
gainLossSummaryItemDetail.AnnualDividend=exposure * weightAdjustedDividendYield;
|
gainLossSummaryItemDetail.AnnualDividend = exposure * weightAdjustedDividendYield;
|
||||||
}
|
}
|
||||||
Prices prices = GLPriceCache.GetInstance().GetPrices(gainLossSummaryItem.Symbol, currentDate, 3); // cache should be refreshed after GainLossSummaryItemCollection
|
|
||||||
Price p1 = prices.Count>0?prices[0]:default;
|
// Cache is already primed pure memory read
|
||||||
Price p2 = prices.Count>1?prices[1]:default;
|
Prices prices = GLPriceCache.GetInstance().GetPrices(gainLossSummaryItem.Symbol, currentDate, 3);
|
||||||
PortfolioTrades symbolTrades = new PortfolioTrades(portfolioTrades.Where(x=>x.Symbol.Equals(gainLossSummaryItem.Symbol)).ToList());
|
Price p1 = prices.Count > 0 ? prices[0] : default;
|
||||||
ParityElement parityElement = ParityGenerator.GenerateBreakEven(symbolTrades, p1);
|
Price p2 = prices.Count > 1 ? prices[1] : default;
|
||||||
gainLossSummaryItemDetail.ParityElement=parityElement;
|
|
||||||
if (null != parityElement)
|
PortfolioTrades tradesForSymbol = new PortfolioTrades(symbolTrades.Where(x => x.Symbol.Equals(gainLossSummaryItem.Symbol)).ToList());
|
||||||
|
ParityElement parityElement = ParityGenerator.GenerateBreakEven(tradesForSymbol, p1);
|
||||||
|
gainLossSummaryItemDetail.ParityElement = parityElement;
|
||||||
|
|
||||||
|
if (null != parityElement && null != gainLossItem)
|
||||||
{
|
{
|
||||||
gainLossSummaryItemDetail.AllTimeGainLossPercent=gainLossItem.GainLossPercent;
|
gainLossSummaryItemDetail.AllTimeGainLossPercent = gainLossItem.GainLossPercent;
|
||||||
gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent=parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100);
|
gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent = parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100);
|
||||||
}
|
}
|
||||||
if(null!=p1 && null!=p2)
|
|
||||||
|
if (null != p1 && null != p2)
|
||||||
{
|
{
|
||||||
double change = (p1.Close - p2.Close) / p2.Close;
|
double change = (p1.Close - p2.Close) / p2.Close;
|
||||||
gainLossSummaryItemDetail.LatestPrice=p1;
|
gainLossSummaryItemDetail.LatestPrice = p1;
|
||||||
gainLossSummaryItemDetail.PriceChange=change;
|
gainLossSummaryItemDetail.PriceChange = change;
|
||||||
}
|
}
|
||||||
|
|
||||||
gainLossSummaryItemDetailCollection.Add(gainLossSummaryItemDetail);
|
gainLossSummaryItemDetailCollection.Add(gainLossSummaryItemDetail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,16 +425,17 @@ namespace MarketDataServer.Controllers
|
|||||||
GainLossSummaryItemDetail gainLossSummaryTotals = new GainLossSummaryItemDetail();
|
GainLossSummaryItemDetail gainLossSummaryTotals = new GainLossSummaryItemDetail();
|
||||||
gainLossSummaryTotals.Symbol = "";
|
gainLossSummaryTotals.Symbol = "";
|
||||||
gainLossSummaryTotals.CompanyName = "Account Summary";
|
gainLossSummaryTotals.CompanyName = "Account Summary";
|
||||||
|
|
||||||
if (null != gainLossSummaryItemDetailCollection && gainLossSummaryItemDetailCollection.Count > 0)
|
if (null != gainLossSummaryItemDetailCollection && gainLossSummaryItemDetailCollection.Count > 0)
|
||||||
{
|
{
|
||||||
gainLossSummaryTotals.Date = gainLossSummaryItemDetailCollection.Min(x => x.Date);
|
gainLossSummaryTotals.Date = gainLossSummaryItemDetailCollection.Min(x => x.Date);
|
||||||
gainLossSummaryTotals.Exposure=gainLossSummaryItemDetailCollection.Sum(x=>x.Exposure);
|
gainLossSummaryTotals.Exposure = gainLossSummaryItemDetailCollection.Sum(x => x.Exposure);
|
||||||
gainLossSummaryTotals.Change = gainLossSummaryItemDetailCollection.Sum(x => x.Change);
|
gainLossSummaryTotals.Change = gainLossSummaryItemDetailCollection.Sum(x => x.Change);
|
||||||
gainLossSummaryTotals.CurrentGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.CurrentGainLoss);
|
gainLossSummaryTotals.CurrentGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.CurrentGainLoss);
|
||||||
gainLossSummaryTotals.PreviousGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.PreviousGainLoss);
|
gainLossSummaryTotals.PreviousGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.PreviousGainLoss);
|
||||||
gainLossSummaryTotals.ChangePercent = ((gainLossSummaryTotals.CurrentGainLoss - gainLossSummaryTotals.PreviousGainLoss) / Math.Abs(gainLossSummaryTotals.PreviousGainLoss)) * 100.00;
|
gainLossSummaryTotals.ChangePercent = ((gainLossSummaryTotals.CurrentGainLoss - gainLossSummaryTotals.PreviousGainLoss) / Math.Abs(gainLossSummaryTotals.PreviousGainLoss)) * 100.00;
|
||||||
gainLossSummaryTotals.LatestPrice=new Price();
|
gainLossSummaryTotals.LatestPrice = new Price();
|
||||||
gainLossSummaryTotals.PriceChange=0;
|
gainLossSummaryTotals.PriceChange = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -309,20 +448,116 @@ namespace MarketDataServer.Controllers
|
|||||||
gainLossSummaryTotals.PriceChange = 0;
|
gainLossSummaryTotals.PriceChange = 0;
|
||||||
}
|
}
|
||||||
gainLossSummaryItemDetailCollection.Insert(0, gainLossSummaryTotals);
|
gainLossSummaryItemDetailCollection.Insert(0, gainLossSummaryTotals);
|
||||||
// ****
|
|
||||||
return gainLossSummaryItemDetailCollection;
|
return gainLossSummaryItemDetailCollection;
|
||||||
}
|
}
|
||||||
catch(Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}");
|
MDTrace.WriteLine(LogLevel.DEBUG, $"Exception:{exception.ToString()}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)");
|
MDTrace.WriteLine(LogLevel.DEBUG, $"Done, total took {profiler.End()} (ms)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [HttpGet]
|
||||||
|
// public IEnumerable<GainLossSummaryItemDetail> GetGainLossWithDetailByDateAndAccount(String token, DateTime selectedDate, String account)
|
||||||
|
// {
|
||||||
|
// Profiler profiler = new Profiler();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// MDTrace.WriteLine(LogLevel.DEBUG,$"Start");
|
||||||
|
// if (!Authorizations.GetInstance().IsAuthorized(token)) return null;
|
||||||
|
// GLPriceCache.GetInstance().Refresh();
|
||||||
|
// PortfolioTrades portfolioTrades = PortfolioDA.GetTrades();
|
||||||
|
// portfolioTrades = new PortfolioTrades(portfolioTrades.Where(x => x.Account.Equals(account)).ToList());
|
||||||
|
// PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate);
|
||||||
|
// GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate);
|
||||||
|
// List<String> symbols = gainLossSummaryItems.Select(x => x.Symbol).ToList();
|
||||||
|
// Dictionary<String,DateTime> latestDates = PricingDA.GetLatestDates(symbols);
|
||||||
|
|
||||||
|
// List<GainLossSummaryItemDetail> gainLossSummaryItemDetailCollection=new List<GainLossSummaryItemDetail>();
|
||||||
|
// foreach(GainLossSummaryItem gainLossSummaryItem in gainLossSummaryItems)
|
||||||
|
// {
|
||||||
|
// GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem);
|
||||||
|
// portfolioTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol);
|
||||||
|
// double weightAdjustedDividendYield = portfolioTrades.GetWeightAdjustedDividendYield();
|
||||||
|
// DateTime currentDate = latestDates[gainLossSummaryItem.Symbol];
|
||||||
|
// if(null==portfolioTrades||0==portfolioTrades.Count)continue;
|
||||||
|
// double shares = (from PortfolioTrade portfolioTrade in portfolioTrades select portfolioTrade.Shares).Sum();
|
||||||
|
// double exposure = portfolioTrades.Sum(x => x.Exposure());
|
||||||
|
// if(null==gainLossGenerator) gainLossGenerator=new ActiveGainLossGenerator();
|
||||||
|
// GainLossCollection gainLoss = gainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions
|
||||||
|
// GainLossItem gainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault();
|
||||||
|
// gainLossSummaryItemDetail.Lots=portfolioTrades.Count;
|
||||||
|
// gainLossSummaryItemDetail.Shares=shares;
|
||||||
|
// gainLossSummaryItemDetail.Exposure=exposure;
|
||||||
|
// if (!double.IsNaN(weightAdjustedDividendYield))
|
||||||
|
// {
|
||||||
|
// gainLossSummaryItemDetail.DividendYield=weightAdjustedDividendYield;
|
||||||
|
// gainLossSummaryItemDetail.AnnualDividend=exposure * weightAdjustedDividendYield;
|
||||||
|
// }
|
||||||
|
// Prices prices = GLPriceCache.GetInstance().GetPrices(gainLossSummaryItem.Symbol, currentDate, 3); // cache should be refreshed after GainLossSummaryItemCollection
|
||||||
|
// Price p1 = prices.Count>0?prices[0]:default;
|
||||||
|
// Price p2 = prices.Count>1?prices[1]:default;
|
||||||
|
// PortfolioTrades symbolTrades = new PortfolioTrades(portfolioTrades.Where(x=>x.Symbol.Equals(gainLossSummaryItem.Symbol)).ToList());
|
||||||
|
// ParityElement parityElement = ParityGenerator.GenerateBreakEven(symbolTrades, p1);
|
||||||
|
// gainLossSummaryItemDetail.ParityElement=parityElement;
|
||||||
|
// if (null != parityElement)
|
||||||
|
// {
|
||||||
|
// gainLossSummaryItemDetail.AllTimeGainLossPercent=gainLossItem.GainLossPercent;
|
||||||
|
// gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent=parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100);
|
||||||
|
// }
|
||||||
|
// if(null!=p1 && null!=p2)
|
||||||
|
// {
|
||||||
|
// double change = (p1.Close - p2.Close) / p2.Close;
|
||||||
|
// gainLossSummaryItemDetail.LatestPrice=p1;
|
||||||
|
// gainLossSummaryItemDetail.PriceChange=change;
|
||||||
|
// }
|
||||||
|
// gainLossSummaryItemDetailCollection.Add(gainLossSummaryItemDetail);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // **** Add an aggregate entry
|
||||||
|
// GainLossSummaryItemDetail gainLossSummaryTotals = new GainLossSummaryItemDetail();
|
||||||
|
// gainLossSummaryTotals.Symbol = "";
|
||||||
|
// gainLossSummaryTotals.CompanyName = "Account Summary";
|
||||||
|
// if (null != gainLossSummaryItemDetailCollection && gainLossSummaryItemDetailCollection.Count > 0)
|
||||||
|
// {
|
||||||
|
// gainLossSummaryTotals.Date = gainLossSummaryItemDetailCollection.Min(x => x.Date);
|
||||||
|
// gainLossSummaryTotals.Exposure=gainLossSummaryItemDetailCollection.Sum(x=>x.Exposure);
|
||||||
|
// gainLossSummaryTotals.Change = gainLossSummaryItemDetailCollection.Sum(x => x.Change);
|
||||||
|
// gainLossSummaryTotals.CurrentGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.CurrentGainLoss);
|
||||||
|
// gainLossSummaryTotals.PreviousGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.PreviousGainLoss);
|
||||||
|
// gainLossSummaryTotals.ChangePercent = ((gainLossSummaryTotals.CurrentGainLoss - gainLossSummaryTotals.PreviousGainLoss) / Math.Abs(gainLossSummaryTotals.PreviousGainLoss)) * 100.00;
|
||||||
|
// gainLossSummaryTotals.LatestPrice=new Price();
|
||||||
|
// gainLossSummaryTotals.PriceChange=0;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// gainLossSummaryTotals.Date = selectedDate;
|
||||||
|
// gainLossSummaryTotals.Change = 0.00;
|
||||||
|
// gainLossSummaryTotals.CurrentGainLoss = 0.00;
|
||||||
|
// gainLossSummaryTotals.PreviousGainLoss = 0.00;
|
||||||
|
// gainLossSummaryTotals.ChangePercent = 0.00;
|
||||||
|
// gainLossSummaryTotals.LatestPrice = new Price();
|
||||||
|
// gainLossSummaryTotals.PriceChange = 0;
|
||||||
|
// }
|
||||||
|
// gainLossSummaryItemDetailCollection.Insert(0, gainLossSummaryTotals);
|
||||||
|
// // ****
|
||||||
|
// return gainLossSummaryItemDetailCollection;
|
||||||
|
// }
|
||||||
|
// catch(Exception exception)
|
||||||
|
// {
|
||||||
|
// MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}");
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// finally
|
||||||
|
// {
|
||||||
|
// MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
[HttpGet(Name = "GetCompoundGainLoss")]
|
[HttpGet(Name = "GetCompoundGainLoss")]
|
||||||
public GainLossCompoundModelCollection GetCompoundGainLoss(String token, int selectedDays, bool includeDividends)
|
public GainLossCompoundModelCollection GetCompoundGainLoss(String token, int selectedDays, bool includeDividends)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user