完成 冬
import java.util.List;
import java.util.Scanner;
public class Main {
private static final String STOCKS_FILE = "stocks.csv";
private static final String TRADES_FILE = "trades.csv";
private static final String MARKET_VALUE_FILE = "marketValue.csv";
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
HandleFile handleFile = new HandleFile();
System.out.println("株式取引管理システムを開始します。");
while (true) {
System.out.println("操作するメニューを選んでください。");
System.out.println("1.銘柄マスタ一覧表示");
System.out.println("2.銘柄マスタ新規登録");
System.out.println("3.取引入力");
System.out.println("4.取引一覧の表示");
System.out.println("5.保有ポジション表示");
System.out.println("9.アプリケーションを終了する");
boolean invalidInput = true;
while (invalidInput) {
System.out.print("入力してください:");
String userInput = scanner.nextLine();
switch (userInput) {
case "1":
System.out.println("銘柄マスタを表示します。");
List<Stock> stocks = handleFile.readStocksFromFile(STOCKS_FILE);
DisplayStocks displayStocks = new DisplayStocks(stocks);
displayStocks.displayStockList();
System.out.println("---");
invalidInput = false;
break;
case "2":
System.out.println("新規株式銘柄マスタを登録します。");
List<Stock> stocksForRegistration = handleFile.readStocksFromFile(STOCKS_FILE);
RegisterStock registerStock = new RegisterStock(stocksForRegistration, STOCKS_FILE);
registerStock.registerNewStocks();
System.out.println("---");
invalidInput = false;
break;
case "3":
System.out.println("取引入力を開始します。");
List<Stock> stocksForTrade = handleFile.readStocksFromFile(STOCKS_FILE);
RegisterTrade registerTrade = new RegisterTrade(stocksForTrade, TRADES_FILE);
registerTrade.registerTrade();
System.out.println("---");
invalidInput = false;
break;
case "4":
System.out.println("取引一覧を表示します。");
List<Trade> trades = handleFile.readTradesFromFile(TRADES_FILE);
DisplayTrades displayTrades = new DisplayTrades(trades);
displayTrades.displayTradeList();
System.out.println("---");
invalidInput = false;
break;
case "5":
System.out.println("保有ポジションを表示します。");
// データ読み込み
List<Trade> allTrades = handleFile.readTradesFromFile(TRADES_FILE);
List<MarketValue> marketValues = handleFile.readMarketValuesFromFile(MARKET_VALUE_FILE);
// 保有数量計算
CalculateQuantity calculateQuantity = new CalculateQuantity();
List<HoldingPosition> positions = calculateQuantity.calculateQuantity(allTrades);
CalculateAvgUnitPrice calculateAvgUnitPrice = new CalculateAvgUnitPrice();
List<HoldingPositionWithAveragePrice> positionsWithAvgPrice = calculateAvgUnitPrice.calculateAverageUnitPrice(allTrades);
OrganizePnL organizePnL = new OrganizePnL(positionsWithAvgPrice, marketValues);
List<HoldingPositionWithPnL> positionsWithPnL = organizePnL.organize(allTrades);
DisplayHoldingPosition displayHolding = new DisplayHoldingPosition(positionsWithPnL);
displayHolding.displayHoldingList();
break;
case "9":
System.out.println("アプリケーションを終了します。");
return;
default:
System.out.println("\"" + userInput + "\"に対応するメニューは存在しません。");
}
}
}
}
}
import java.math.BigDecimal;
public class HoldingPositionWithAveragePrice extends HoldingPosition {
private final BigDecimal averageUnitPrice;
public HoldingPositionWithAveragePrice(String ticker, String productName, long quantity, BigDecimal averageUnitPrice) {
super(ticker, productName, quantity);
this.averageUnitPrice = averageUnitPrice;
}
public BigDecimal getAverageUnitPrice() {
return averageUnitPrice;
}
}
import java.math.BigDecimal;
public class HoldingPositionWithPnL extends HoldingPositionWithAveragePrice {
private final BigDecimal valuation;
private final BigDecimal realizedPnL;
private final BigDecimal unrealizedPnL;
public HoldingPositionWithPnL(
String ticker,
String productName,
long quantity,
BigDecimal averageUnitPrice,
BigDecimal valuation,
BigDecimal realizedPnL,
BigDecimal unrealizedPnL
) {
super(ticker, productName, quantity, averageUnitPrice);
this.valuation = valuation;
this.realizedPnL = realizedPnL;
this.unrealizedPnL = unrealizedPnL;
}
public BigDecimal getValuation() {
return valuation;
}
public BigDecimal getRealizedPnL() {
return realizedPnL;
}
public BigDecimal getUnrealizedPnL() {
return unrealizedPnL;
}
}
import java.text.DecimalFormat;
import java.util.Comparator;
import java.util.List;
public class DisplayHoldingPosition {
private final List<HoldingPositionWithPnL> positions;
public DisplayHoldingPosition(List<HoldingPositionWithPnL> positions) {
this.positions = positions;
}
public void displayHoldingList() {
positions.sort(Comparator.comparing(HoldingPositionWithPnL::getTicker));
DecimalFormat decimalFormat = new DecimalFormat("##,###.###");
// 表ヘッダー
System.out.println("┌────────┬────────────────────────────────┬──────────────────┬───────────────┬──────────────┬──────────────┬──────────────┐");
System.out.printf("│ %-6s │ %-30s │ %-16s │ %-13s │ %-12s │ %-12s │ %-12s │%n",
"Ticker", "Product Name", "Quantity", "Avg Price", "Valuation", "Realized P&L", "Unrealized P&L");
System.out.println("├────────┼────────────────────────────────┼──────────────────┼───────────────┼──────────────┼──────────────┼──────────────┤");
// 表内容
for (HoldingPositionWithPnL position : positions) {
System.out.printf("│ %-6s │ %-30s │ %,16d │ %,13.2f │ %,12s │ %,12.2f │ %,12s │%n",
position.getTicker(),
position.getProductName(),
position.getQuantity(),
decimalFormat.format(position.getAverageUnitPrice()),
decimalFormat.format(position.getValuation() != null ? position.getValuation() : "N/A"),
decimalFormat.format(position.getRealizedPnL()),
decimalFormat.format(position.getUnrealizedPnL() != null ? position.getUnrealizedPnL() : "N/A"));
}
// 表フッター
System.out.println("└────────┴────────────────────────────────┴──────────────────┴───────────────┴──────────────┴──────────────┴──────────────┘");
}
}
import java.util.ArrayList;
import java.util.List;
public class CalculateQuantity {
public List<HoldingPosition> calculateQuantity(List<Trade> trades) {
List<HoldingPosition> positions = new ArrayList<>();
for (Trade trade : trades) {
long quantity = 0;
if (trade.getSide() == SideType.BUY) {
quantity = trade.getQuantity();
} else if (trade.getSide() == SideType.SELL) {
quantity = -trade.getQuantity();
}
String ticker = trade.getTicker();
HoldingPosition updatedPosition = null;
for (HoldingPosition position : positions) {
if (position.getTicker().equals(ticker)) {
long updatedQuantity = position.getQuantity() + quantity;
updatedPosition = new HoldingPosition(position.getTicker(), position.getProductName(), updatedQuantity);
positions.remove(position);
break;
}
}
if (updatedPosition == null) {
updatedPosition = new HoldingPosition(ticker, trade.getProductName(), quantity);
}
positions.add(updatedPosition);
}
return positions;
}
}
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
public class CalculateAvgUnitPrice {
private final List<HoldingPositionWithAveragePrice> positions;
public CalculateAvgUnitPrice() {
this.positions = new ArrayList<>();
}
public List<HoldingPositionWithAveragePrice> calculateAverageUnitPrice(List<Trade> trades) {
for (Trade trade : trades) {
String ticker = trade.getTicker();
BigDecimal tradedUnitPrice = trade.getTradedUnitPrice();
long tradeQuantity = trade.getQuantity();
HoldingPositionWithAveragePrice existingPosition = getPositionByTicker(ticker);
if (existingPosition == null) {
BigDecimal initialAveragePrice = BigDecimal.ZERO;
if (trade.getSide() == SideType.BUY) {
initialAveragePrice = tradedUnitPrice;
}
positions.add(new HoldingPositionWithAveragePrice(
ticker,
trade.getProductName(),
tradeQuantity,
initialAveragePrice
));
} else {
if (trade.getSide() == SideType.BUY) {
positions.remove(existingPosition);
positions.add(createUpdatedPositionForBuy(existingPosition, tradeQuantity, tradedUnitPrice));
} else {
positions.remove(existingPosition);
positions.add(createUpdatedPositionForSell(existingPosition, tradeQuantity));
}
}
}
return positions;
}
private HoldingPositionWithAveragePrice getPositionByTicker(String ticker) {
for (HoldingPositionWithAveragePrice position : positions) {
if (position.getTicker().equals(ticker)) {
return position;
}
}
return null;
}
private HoldingPositionWithAveragePrice createUpdatedPositionForBuy(
HoldingPositionWithAveragePrice position,
long tradeQuantity,
BigDecimal tradedUnitPrice
) {
long previousQuantity = position.getQuantity();
BigDecimal previousAveragePrice = position.getAverageUnitPrice();
BigDecimal totalCost = previousAveragePrice.multiply(BigDecimal.valueOf(previousQuantity))
.add(tradedUnitPrice.multiply(BigDecimal.valueOf(tradeQuantity)));
long newQuantity = previousQuantity + tradeQuantity;
BigDecimal newAveragePrice = totalCost.divide(BigDecimal.valueOf(newQuantity), 2, RoundingMode.HALF_UP);
return new HoldingPositionWithAveragePrice(
position.getTicker(),
position.getProductName(),
newQuantity,
newAveragePrice
);
}
private HoldingPositionWithAveragePrice createUpdatedPositionForSell(
HoldingPositionWithAveragePrice position,
long tradeQuantity
) {
long previousQuantity = position.getQuantity();
long newQuantity = previousQuantity - tradeQuantity;
return new HoldingPositionWithAveragePrice(
position.getTicker(),
position.getProductName(),
newQuantity,
position.getAverageUnitPrice()
);
}
}
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
public class CalculateRealizedPnL {
public BigDecimal calculate(List<Trade> trades, List<HoldingPositionWithAveragePrice> positions, String ticker) {
BigDecimal realizedPnL = BigDecimal.ZERO;
// HoldingPositionWithAveragePrice から該当ティッカーの平均取得単価を取得
BigDecimal averageUnitPrice = getAverageUnitPriceByTicker(positions, ticker);
for (Trade trade : trades) {
if (trade.getTicker().equals(ticker) && trade.getSide() == SideType.SELL) {
BigDecimal tradePnL = BigDecimal.valueOf(trade.getQuantity())
.multiply(trade.getTradedUnitPrice().subtract(averageUnitPrice));
realizedPnL = realizedPnL.add(tradePnL);
}
}
return realizedPnL.setScale(2, RoundingMode.HALF_UP);
}
private BigDecimal getAverageUnitPriceByTicker(List<HoldingPositionWithAveragePrice> positions, String ticker) {
for (HoldingPositionWithAveragePrice position : positions) {
if (position.getTicker().equals(ticker)) {
return position.getAverageUnitPrice();
}
}
return null; // 該当ティッカーがない場合
}
}
import java.math.BigDecimal;
import java.math.RoundingMode;
public class CalculateUnrealizedPnL {
public BigDecimal calculate(long quantity, BigDecimal avgUnitPrice, BigDecimal valuation) {
if (valuation == null) {
return null; // 時価が取得できない場合
}
BigDecimal cost = BigDecimal.valueOf(quantity).multiply(avgUnitPrice);
return valuation.subtract(cost).setScale(2, RoundingMode.HALF_UP);
}
}
import java.math.BigDecimal;
import java.math.RoundingMode;
public class CalculateValuation {
public BigDecimal calculate(long quantity, BigDecimal marketPrice) {
if (marketPrice == null) {
return null; // 時価が取得できない場合
}
return BigDecimal.valueOf(quantity).multiply(marketPrice).setScale(2, RoundingMode.HALF_UP);
}
}
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class OrganizePnL {
private final List<HoldingPositionWithAveragePrice> positions;
private final List<MarketValue> marketValues;
public OrganizePnL(List<HoldingPositionWithAveragePrice> positions, List<MarketValue> marketValues) {
this.positions = positions;
this.marketValues = marketValues;
}
public List<HoldingPositionWithPnL> organize(List<Trade> trades) {
List<HoldingPositionWithPnL> result = new ArrayList<>();
CalculateRealizedPnL calculateRealizedPnL = new CalculateRealizedPnL();
CalculateValuation calculateValuation = new CalculateValuation();
CalculateUnrealizedPnL calculateUnrealizedPnL = new CalculateUnrealizedPnL();
for (HoldingPositionWithAveragePrice position : positions) {
String ticker = position.getTicker();
long holdingQuantity = position.getQuantity();
BigDecimal avgUnitPrice = position.getAverageUnitPrice();
// 時価を取得
BigDecimal marketPrice = getMarketPriceByTicker(ticker);
// Valuation
BigDecimal valuation = calculateValuation.calculate(holdingQuantity, marketPrice);
// Unrealized P&L
BigDecimal unrealizedPnL = calculateUnrealizedPnL.calculate(holdingQuantity, avgUnitPrice, valuation);
// Realized P&L
BigDecimal realizedPnL = calculateRealizedPnL.calculate(trades, positions, ticker);
result.add(new HoldingPositionWithPnL(
ticker,
position.getProductName(),
holdingQuantity,
avgUnitPrice,
valuation,
realizedPnL,
unrealizedPnL
));
}
return result;
}
private BigDecimal getMarketPriceByTicker(String ticker) {
for (MarketValue marketValue : marketValues) {
if (marketValue.getTicker().equals(ticker)) {
return marketValue.getMarketPrice();
}
}
return null; // 時価が取得できない場合
}
}