143 lines
5.0 KiB
C#
Executable File
143 lines
5.0 KiB
C#
Executable File
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using MarketData.Generator.GainLoss;
|
|
using MarketData.DataAccess;
|
|
using MarketData.MarketDataModel;
|
|
using MarketData.Utils;
|
|
|
|
|
|
namespace MarketData.Generator
|
|
{
|
|
public class ParityGenerator
|
|
{
|
|
private enum Direction { Negative, Positive, None };
|
|
private ParityGenerator()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given PortfolioTrades for a symbol and corresponding latestPrice gives us the breakeven element.
|
|
/// This call avoid calling the database. Used by GetGainLossWithDetailByDate in the GainLossController
|
|
/// </summary>
|
|
/// <param name="symbolTrades"></param>
|
|
/// <param name="latestPrice"></param>
|
|
/// <returns></returns>
|
|
public static ParityElement GenerateBreakEven(PortfolioTrades symbolTrades,Price latestPrice)
|
|
{
|
|
try
|
|
{
|
|
ParityElement parityElement=new ParityElement();
|
|
Price zeroPrice=null;
|
|
if(null==symbolTrades||0==symbolTrades.Count)return null;
|
|
PortfolioTrades openTrades=symbolTrades.GetOpenTrades();
|
|
GainLossGenerator gainLossGenerator=new GainLossGenerator();
|
|
zeroPrice=ParityGenerator.GenerateGainLossValue(openTrades,latestPrice);
|
|
parityElement.ParityOffsetPrice=zeroPrice.Close;
|
|
parityElement.ParityOffsetPercent=((latestPrice.Close-zeroPrice.Close)/zeroPrice.Close);
|
|
parityElement.Symbol=latestPrice.Symbol;
|
|
parityElement.PricingDate=latestPrice.Date;
|
|
return parityElement;
|
|
}
|
|
catch(Exception exception)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0}",exception));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static ParityElement GenerateBreakEven(String symbol)
|
|
{
|
|
try
|
|
{
|
|
ParityElement parityElement=new ParityElement();
|
|
Price zeroPrice=null;
|
|
PortfolioTrades portfolioTrades = PortfolioDA.GetTradesSymbol(symbol);
|
|
if(null==portfolioTrades||0==portfolioTrades.Count)return null;
|
|
PortfolioTrades openTrades=portfolioTrades.GetOpenTrades();
|
|
DateTime pricingDate = PricingDA.GetLatestDate(symbol);
|
|
Price latestPrice = PricingDA.GetPrice(symbol, pricingDate);
|
|
GainLossGenerator gainLossGenerator=new GainLossGenerator();
|
|
zeroPrice=ParityGenerator.GenerateGainLossValue(openTrades,latestPrice);
|
|
parityElement.ParityOffsetPrice=zeroPrice.Close;
|
|
parityElement.ParityOffsetPercent=((latestPrice.Close-zeroPrice.Close)/zeroPrice.Close);
|
|
parityElement.Symbol=symbol;
|
|
parityElement.PricingDate=pricingDate;
|
|
return parityElement;
|
|
}
|
|
catch(Exception exception)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0}",exception));
|
|
return null;
|
|
}
|
|
}
|
|
// generate gain/loss value for portfolio of like symbols
|
|
// This funtion will return the dollar price that the stock must either rise to (when G/L is negative) or fall to (when the G/L is positive)
|
|
// in order to produce a zero return (i.e.) a wash.
|
|
public static Price GenerateGainLossValue(PortfolioTrades portfolioTrades,Price givenPrice)
|
|
{
|
|
double? lowerClamp=null;
|
|
double? upperClamp=null;
|
|
double? gainLoss=null;
|
|
double? prevGuess=null;
|
|
Direction direction=Direction.None;
|
|
int iterations=0;
|
|
|
|
if(null==portfolioTrades||0==portfolioTrades.Count) return null;
|
|
Price price=givenPrice.Clone();
|
|
gainLoss=portfolioTrades.GetGainLoss(price);
|
|
if(gainLoss<0) direction=Direction.Negative;
|
|
else direction=Direction.Positive;
|
|
while(true)
|
|
{
|
|
if(IsZero(gainLoss)) break;
|
|
if(null==lowerClamp&&null==upperClamp&&gainLoss<0&&direction.Equals(Direction.Negative))
|
|
{
|
|
prevGuess=price.Close;
|
|
price.Close=price.Close+(price.Close/2.00);
|
|
iterations++;
|
|
}
|
|
else if(null==lowerClamp&&null==upperClamp&&gainLoss>=0&&direction.Equals(Direction.Positive))
|
|
{
|
|
prevGuess=price.Close;
|
|
price.Close=price.Close-(price.Close/2.00);
|
|
iterations++;
|
|
}
|
|
else
|
|
{
|
|
if(gainLoss<0)
|
|
{
|
|
lowerClamp=price.Close;
|
|
if(null==upperClamp) upperClamp=prevGuess;
|
|
price.Close=(lowerClamp.Value+upperClamp.Value)/2.00;
|
|
prevGuess=price.Close;
|
|
iterations++;
|
|
}
|
|
else
|
|
{
|
|
upperClamp=price.Close;
|
|
if(null==lowerClamp) lowerClamp=prevGuess;
|
|
price.Close=(upperClamp.Value+lowerClamp.Value)/2.00;
|
|
prevGuess=price.Close;
|
|
iterations++;
|
|
}
|
|
}
|
|
gainLoss=portfolioTrades.GetGainLoss(price);
|
|
}
|
|
return price;
|
|
}
|
|
public static bool IsZero(double? value)
|
|
{
|
|
if(null==value)
|
|
{
|
|
return true;
|
|
}
|
|
int intValue=(int)(value*10000.00);
|
|
if(0==intValue) return true;
|
|
return false;
|
|
}
|
|
}
|
|
}
|