public void MatchFound(SingleTransaction first, SingleTransaction matched, bool firstPartialMatch, bool secondPartialMatch) { double spunit = 0; double cpunit = 0; double gainlossunit = 0; double thistransgainorloss = 0.0; double returnOnInvestment = 0.0; double roIAnnualized = 0.0; if (first.TransactionDate.CompareTo(matched.TransactionDate) < 0) { spunit = Convert.ToDouble(matched.TransactionPrice - matched.UnitCharges); cpunit = Convert.ToDouble(first.TransactionPrice + first.UnitCharges); } else { spunit = Convert.ToDouble(first.TransactionPrice - first.UnitCharges); cpunit = Convert.ToDouble(matched.TransactionPrice + matched.UnitCharges); } gainlossunit = spunit - cpunit; SingleTransaction selltrans = null; if (first.IsDisposal()) selltrans = first; else selltrans = matched; TimeSpan ts = new TimeSpan(); ts = matched.TransactionDate - first.TransactionDate; int days = ts.Days; if (days < 0) days *= -1; double yearsheld = Convert.ToDouble(days) / 365; double baseamount = 0; if (!selltrans.IsRemoval()) // if this is a removal there is no gain or loss. { thistransgainorloss = gainlossunit * first.TransactionQty; gainorloss = gainorloss + thistransgainorloss; totalshortterm += thistransgainorloss; baseamount = Convert.ToDouble(first.TransactionPrice * first.TransactionQty) + Convert.ToDouble(first.transactionCharges) + Convert.ToDouble(matched.transactionCharges); returnOnInvestment = (thistransgainorloss / baseamount); if (returnOnInvestment < 0) { roIAnnualized = -1 * (Math.Pow((-1*returnOnInvestment)+1, (1 / yearsheld))-1); } else { roIAnnualized = Math.Pow(returnOnInvestment+1, (1 / yearsheld)) -1; } } OutputHelper.PrintRoI(first, matched, thistransgainorloss, days, (returnOnInvestment*100), (roIAnnualized*100), header); header = false; }
void IStockMatch.MatchFound(SingleTransaction first, SingleTransaction matched, bool firstPartialMatch, bool secondPartialMatch) { decimal spunit = 0.0M; decimal cpunit = 0.0M; decimal gainlossunit = 0.0M; decimal tshortterm = 0.0M; decimal tlongterm = 0.0M; if (first.TransactionDate.CompareTo(matched.TransactionDate) < 0) { spunit = matched.TransactionPrice - matched.UnitCharges; cpunit = first.TransactionPrice + first.UnitCharges; } else { spunit = first.TransactionPrice - first.UnitCharges; cpunit = matched.TransactionPrice + matched.UnitCharges; } gainlossunit = spunit - cpunit; SingleTransaction selltrans = null; if (first.IsDisposal()) selltrans = first; else selltrans = matched; if (selltrans.TransactionDate.CompareTo(fromdate) >= 0 && selltrans.TransactionDate.CompareTo(todate) <= 0) { atLeastOneTrans = true; TimeSpan ts = new TimeSpan(); ts = matched.TransactionDate - first.TransactionDate; int days = ts.Days; if (days < 0) days *= -1; if (!selltrans.IsRemoval()) // if this is a removal there is no gain or loss. { if (days < longtermdays || gainlossunit < 0) { tshortterm = gainlossunit * first.TransactionQty; shortterm += tshortterm; totalshortterm += tshortterm; tlongterm = 0.0M; } else { tlongterm = gainlossunit * first.TransactionQty; longterm += tlongterm; totallongterm += tlongterm; tshortterm = 0.0M; } } Helpers.OutputHelper.PrintGains(first, matched, tshortterm, tlongterm, header); header = false; } }
}// StockTaking public void CapitalGains(System.DateTime fromdate, System.DateTime todate, int longtermdays) { // Sort transactions by stock code. // Data structure is a Hashtable of StockCode (Key) to ArrayList of SingleTransaction (value) Hashtable mystocktable = new Hashtable(); if (!SortTransactionsByStockCode(out mystocktable)) return; decimal totallongterm = 0.0M; decimal totalshortterm = 0.0M; // Now process each stock bool header = true; bool bAtLeastOneTransForThisStock = false; foreach (String stock in mystocktable.Keys) { ArrayList thisStockTransactions = (ArrayList)mystocktable[stock]; header = true; bAtLeastOneTransForThisStock = false; thisStockTransactions.Sort(); bool bfirst = true; long nStockQty = 0; decimal longterm = 0.0M; decimal shortterm = 0.0M; decimal sUnitBrokerage = 0.0M; for (int i=0;i< thisStockTransactions.Count;i++) { SingleTransaction s = (SingleTransaction)thisStockTransactions[i]; if (s.transactionReconciledFlag) continue; sUnitBrokerage = s.transactionCharges/s.transactionQty; if (bfirst) { bfirst = false; if (!s.IsAcquisition()) Console.WriteLine("First transaction for {0} is not a BUY order. ref {1}", s.transactionStockCode, s.transactionLotIdentifier); if (s.IsAcquisition()) nStockQty += s.transactionQty; else nStockQty -= s.transactionQty; } if (s.transactionReconciledFlag) continue; if (nStockQty != 0) { // find matching transaction SingleTransaction.eTransactionType thisttype = s.transactionType; bool restartloop = false; do { restartloop = false; decimal tlongterm = 0.0M; decimal tshortterm = 0.0M; for (int j=i+1; j<thisStockTransactions.Count;j++) { SingleTransaction snext = (SingleTransaction)thisStockTransactions[j]; if (snext.transactionReconciledFlag) continue; if (!snext.IsOppositeType(thisttype) ) continue; if (SingleTransaction.ReferenceEquals(s,snext)) continue; decimal spunit = 0.0M; decimal cpunit = 0.0M;decimal gainlossunit = 0.0M; if (s.transactionDate.CompareTo(snext.transactionDate) < 0) { spunit = snext.transactionPrice - snext.transactionCharges/snext.transactionQty; cpunit = s.transactionPrice + sUnitBrokerage; } else { spunit = s.transactionPrice - sUnitBrokerage; cpunit = snext.transactionPrice + snext.transactionCharges/snext.transactionQty; } gainlossunit = spunit - cpunit; if (nStockQty == snext.transactionQty) { SingleTransaction first = null; if (nStockQty == s.transactionQty) first = s; else first = new SingleTransaction(s.transactionType,s.transactionDate,s.transactionStockCode,nStockQty,s.transactionPrice,s.transactionCharges/s.transactionQty*nStockQty,s.transactionLotIdentifier); SingleTransaction selltrans = null; if (first.IsDisposal()) selltrans = first; else selltrans = snext; if (selltrans.transactionDate.CompareTo(fromdate) >= 0 && selltrans.transactionDate.CompareTo(todate) <= 0) { TimeSpan ts = new TimeSpan(); ts = snext.transactionDate-first.transactionDate; if (ts.Days < longtermdays) { tshortterm = gainlossunit*nStockQty; shortterm += tshortterm; totalshortterm += tshortterm; tlongterm = 0.0M; } else { tlongterm = gainlossunit*nStockQty; longterm += tlongterm; totallongterm += tlongterm; tshortterm = 0.0M; } Helpers.OutputHelper.PrintGains(first,snext,tshortterm,tlongterm,header); header = false; bAtLeastOneTransForThisStock = true; } s.transactionReconciledFlag = true; snext.transactionReconciledFlag = true; nStockQty = 0; bfirst = true; break; } else if (nStockQty > snext.transactionQty) { long qty = snext.transactionQty; SingleTransaction first = new SingleTransaction(s.transactionType,s.transactionDate,s.transactionStockCode,qty,s.transactionPrice,s.transactionCharges/s.transactionQty*qty,s.transactionLotIdentifier); SingleTransaction selltrans = null; if (first.IsDisposal()) selltrans = first; else selltrans = snext; if (selltrans.transactionDate.CompareTo(fromdate) >= 0 && selltrans.transactionDate.CompareTo(todate) <= 0) { TimeSpan ts = new TimeSpan(); ts = snext.transactionDate-first.transactionDate; if (ts.Days < longtermdays) { tshortterm = gainlossunit*qty; shortterm += tshortterm; totalshortterm += tshortterm; tlongterm = 0.0M; } else { tlongterm = gainlossunit*qty; longterm += tlongterm; totallongterm += tlongterm; tshortterm = 0.0M; } Helpers.OutputHelper.PrintGains(first,snext,tshortterm,tlongterm,header); header = false; bAtLeastOneTransForThisStock = true; } nStockQty -= qty; snext.transactionReconciledFlag = true; } else if (nStockQty < snext.transactionQty) { SingleTransaction first = new SingleTransaction(s.transactionType,s.transactionDate,s.transactionStockCode,nStockQty,s.transactionPrice,s.transactionCharges/s.transactionQty*nStockQty,s.transactionLotIdentifier); SingleTransaction second = new SingleTransaction(snext.transactionType,snext.transactionDate,snext.transactionStockCode,nStockQty,snext.transactionPrice,snext.transactionCharges/snext.transactionQty*nStockQty,snext.transactionLotIdentifier); SingleTransaction selltrans = null; if (first.IsDisposal()) selltrans = first; else selltrans = second; int nFrom = selltrans.transactionDate.CompareTo(fromdate); int nTo = selltrans.transactionDate.CompareTo(todate); if ( nFrom >= 0 && nTo <= 0) { TimeSpan ts = new TimeSpan(); ts = second.transactionDate-first.transactionDate; if (ts.Days < longtermdays) { tshortterm = gainlossunit*nStockQty; shortterm += tshortterm; totalshortterm += tshortterm; tlongterm = 0.0M; } else { tlongterm = gainlossunit*nStockQty; longterm += tlongterm; totallongterm += tlongterm; tshortterm = 0.0M; } Helpers.OutputHelper.PrintGains(first,second,tshortterm,tlongterm,header); header = false; bAtLeastOneTransForThisStock = true; } nStockQty = snext.transactionQty - nStockQty; s.transactionReconciledFlag = true; s = snext; sUnitBrokerage = s.transactionCharges/s.transactionQty; thisttype = s.transactionType; restartloop = true; break; } } }while (restartloop); } else bfirst = true; } if (bAtLeastOneTransForThisStock) { Console.WriteLine("{0,110} {1,12:F2} {2,12:F2}", "", shortterm, longterm); Console.WriteLine("---------------------------------------------------------------------------------------------------------------------------------------------"); } } Console.WriteLine("{0,110} {1,12:F2} {2,12:F2}", "", totalshortterm, totallongterm); Console.WriteLine("---------------------------------------------------------------------------------------------------------------------------------------------"); return; }// CapitalGains
// Called each time a matching transaction is found void IStockMatch.MatchFound(SingleTransaction s, SingleTransaction matched, bool firstPartialMatch, bool secondPartialMatch) { // This stock was sold. So remove it from our counting int ret = asofDate.CompareTo(s.TransactionDate); if (ret < 0) { //if (debug) //System.Console.WriteLine("Transaction happened on {0,15:d} after date {1,15:d}. Ignoring...", s.TransactionDate, asofDate); return; } TimeSpan ts = new TimeSpan(); ts = asofDate - s.TransactionDate; if (debug) { s.Dump(); matched.Dump(); } if (matched.IsDisposal()) { thisstockqty -= matched.TransactionQty; if (ts.Days > longtermdays) thisstockqtyLT -= matched.TransactionQty; } else { thisstockqty += matched.TransactionQty; if (ts.Days > longtermdays) thisstockqtyLT += matched.TransactionQty; } if (debug) { System.Console.WriteLine("END MATCH Stock balance for {0,6} as of {1,15:d} is {2,15}. Long term quantities {3,15}", s.StockCode, asofDate, thisstockqty, thisstockqtyLT); System.Console.WriteLine("-----------------------------------------------------------------------------------"); } }