/// <summary> /// Close a position. If not all shares are used, return /// a closed position. Modify position so that it can still be used /// as an open position with the remaining shares. /// If all shares are used, return null; /// </summary> /// <param name="position"></param> /// <param name="stock"></param> /// <param name="sharesToSell"></param> /// <returns></returns> public static Position ClosePosition(Position position, Stock stock, double sharesToSell) { position.CurrentPrice = stock.AdjustedClose; if (Math.Abs(sharesToSell - position.Shares) < Portfolio.Epsilon) { // all shares used up, just close this position and returns null // some bookkeeping position.SoldDate = stock.Date; position.Close = true; return null; } double remainingShares = position.Shares - sharesToSell; // change the position shares position.Shares = remainingShares; // now return a closed position with the shares sold return new Position { // acquired date is the same AcquiredDate = position.AcquiredDate, Shares = sharesToSell, // acquired price is also the same AcquiredPrice = position.AcquiredPrice, CurrentPrice = stock.AdjustedClose, Close = true, SoldDate = stock.Date, Name = stock.Name, Ticker = stock.Ticker }; }
public static Stock ParsePrice(string price, string Ticker, string Name) { string[] values = price.Split(','); Stock result = new Stock(); result.Date = DateTime.Parse(values[0]); result.Open = Double.Parse(values[1]); result.High = Double.Parse(values[2]); result.Low = Double.Parse(values[3]); result.Close = Double.Parse(values[4]); result.Volumn = long.Parse(values[5]); result.AdjustedClose = Double.Parse(values[6]); result.Ticker = Ticker; result.Name = Name; return result; }
/// <summary> /// Buy a stock /// </summary> /// <param name="stock"></param> /// <param name="ticker"></param> public void BuyStock(Stock stock, double money) { if (money > Cash && (Math.Abs(money - Cash) > 0.0005)) { throw new InvalidOperationException("Not enough cash!"); } // let's sese how many shares we can buy double noOfShares = (money - Commission) / stock.AdjustedClose; Cash = Cash - money; // Open a list of position if not already there if (!OpenPositions.ContainsKey(stock.Ticker)) { OpenPositions[stock.Ticker] = new List<Position>(); } // Add to the list of position OpenPositions[stock.Ticker].Add(Position.OpenPosition(stock, noOfShares)); }
public void UpdateOpenPosition(Stock stock) { if (OpenPositions.ContainsKey(stock.Ticker) && OpenPositions[stock.Ticker] != null) { foreach (var position in OpenPositions[stock.Ticker]) { position.CurrentPrice = stock.AdjustedClose; } } }
public void SellStock(Stock stock, double noOfShares) { if (!OpenPositions.ContainsKey(stock.Ticker)) { throw new InvalidOperationException("No stock to sell!"); } if (noOfShares <= Epsilon) { throw new ArgumentException(String.Format("noOfShares {0} is zero or negative", noOfShares)); } // update the current price of all the open positions for this stock UpdateOpenPosition(stock); // check the total number of shares available double totalShares = OpenPositions[stock.Ticker].Sum(position => position.Shares); if (totalShares < noOfShares && Math.Abs(totalShares - noOfShares) < Epsilon) { throw new InvalidOperationException("Not enough shares to sell"); } // add to the close position list if (!ClosedPositions.ContainsKey(stock.Ticker)) { ClosedPositions[stock.Ticker] = new List<Position>(); } // update cash before we sell (greedy hehe) Cash += ((noOfShares * stock.AdjustedClose) - Commission); // for now, we will sell the earliest available one first. // other selling method will be added in the future foreach (var position in OpenPositions[stock.Ticker]) { // checks whether noOfShares are greater than or equal to the amount in this position if (noOfShares > position.Shares || Math.Abs(noOfShares - position.Shares) < Epsilon) { // sell this position // don't care about the return value here because all shares are used up Position.ClosePosition(position, stock, position.Shares); // decrease the share noOfShares -= position.Shares; // add this to the close position ClosedPositions[stock.Ticker].Add(position); UpdatePortfolioAfterClosingPosition(position); if (noOfShares < Epsilon) { break; } } else { // we have enough in this position Position closedPosition = Position.ClosePosition(position, stock, noOfShares); UpdatePortfolioAfterClosingPosition(closedPosition); ClosedPositions[stock.Ticker].Add(closedPosition); } } // remove the closed positions OpenPositions[stock.Ticker].RemoveAll(position => position.Close); }
public double GetStockShares(Stock stock) { if (!OpenPositions.ContainsKey(stock.Ticker) || OpenPositions[stock.Ticker] == null) { return 0; } return OpenPositions[stock.Ticker].Sum(position => position.Shares); }
/// <summary> /// Opens a position /// </summary> /// <param name="stock"></param> public static Position OpenPosition(Stock stock, double shares) { Position position = new Position { AcquiredDate = stock.Date, Shares = shares, AcquiredPrice = stock.AdjustedClose, CurrentPrice = stock.AdjustedClose, Name = stock.Name, Ticker = stock.Ticker }; return position; }