package simplex.bn25.datemasa335859.trading.a;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
public class MarketPriceLoader {
private static final String MARKET_PRICE_FILE_PATH = "trading-app/src/market_price.csv"; // 時価データのCSVファイルパス
private static final Map<String, BigDecimal> MARKET_PRICES = new HashMap<>(); // 銘柄コードと時価のマッピング
// CSVファイルから時価データを読み込むメソッド
public static void loadMarketPrices() {
try (BufferedReader br = new BufferedReader(new FileReader(MARKET_PRICE_FILE_PATH))) {
MARKET_PRICES.clear(); // 既存の時価データをクリアして再読み込み
String line;
// ヘッダー行をスキップ
br.readLine();
while ((line = br.readLine()) != null) {
String[] data = line.split(","); // CSVをカンマで分割
if (data.length == 2) { // 列数が2であることを確認
String ticker = data[0].trim(); // 銘柄コードを取得
String priceString = data[1].trim(); // 時価を取得
if (isValidNumber(priceString)) { // 有効な数値かを確認
try {
BigDecimal price = new BigDecimal(priceString); // 有効な場合のみBigDecimalを作成
MARKET_PRICES.put(ticker, price); // マップに保存
} catch (NumberFormatException e) {
System.out.println("エラー: 不正な時価データが検出されました。スキップします。行: " + line);
}
} else {
System.out.println("エラー: 不正な時価データが検出されました。スキップします。行: " + line);
}
}
}
} catch (IOException e) {
System.out.println("エラー: 時価データの読み込みに失敗しました。");
}
}
// 銘柄コードに対応する時価を取得するメソッド
public static BigDecimal getMarketPrice(String ticker) {
return MARKET_PRICES.get(ticker); // 銘柄コードから時価を取得
}
// 入力文字列が有効な数値かどうかを確認するユーティリティメソッド
private static boolean isValidNumber(String value) {
try {
new BigDecimal(value); // BigDecimalの作成を試みる
return true; // 成功したら有効
} catch (NumberFormatException e) {
return false; // 数値として無効
}
}
}
package simplex.bn25.datemasa335859.trading.a;
import simplex.bn25.datemasa335859.trading.stock.TickerManager;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
public class PositionCalculator {
private final TradeDataLoader tradeDataLoader;
// コンストラクタでTradeDataLoaderのインスタンスを受け取る
public PositionCalculator(TradeDataLoader tradeDataLoader) {
this.tradeDataLoader = tradeDataLoader;
}
// 保有ポジションを計算し、表示するメソッド
public void displayPositions() {
Map<String, Position> positions = tradeDataLoader.calculatePositions();
if (positions.isEmpty()) {
System.out.println("取引データが登録されていません。");
return;
}
// 表のヘッダーを表示
System.out.println("|===============================================================================================================|");
System.out.println("| Ticker | Product Name | Quantity | Avg Unit Price | Realized PnL | Valuation | Unrealized PnL |");
System.out.println("|--------+-------------------------------+------------+------------------+----------------+-------------+----------------|");
// 各ポジションについて情報を表示
for (Map.Entry<String, Position> entry : positions.entrySet()) {
String ticker = entry.getKey();
Position position = entry.getValue();
// tickerNameの取得
String tickerName = TickerManager.getTickerToNameMap().getOrDefault(ticker, "Unknown");
// 時価情報を取得
BigDecimal marketPrice = MarketPriceLoader.getMarketPrice(ticker);
// 評価額を計算
BigDecimal valuation = marketPrice != null
? position.calculateValuation(marketPrice).setScale(2, RoundingMode.HALF_UP)
: null;
// 評価損益を計算
BigDecimal unrealizedPnL = marketPrice != null
? position.calculateUnrealizedPnL(marketPrice).setScale(2, RoundingMode.HALF_UP)
: null;
// 表形式で出力。時価がない場合は"N/A"を表示
System.out.printf("| %-6s | %-29s | %10d | %,16.2f | %-14s | %-11s | %-14s |\n",
ticker,
tickerName,
position.quantity(),
position.getAverageUnitPrice(),
position.getRealizedPnL().compareTo(BigDecimal.ZERO) != 0 ? position.getRealizedPnL() : "N/A",
valuation != null ? valuation : "N/A",
unrealizedPnL != null ? unrealizedPnL : "N/A");
}
// 表のフッターを表示
System.out.println("|===============================================================================================================|");
}
}
下記は修正の必要かもしれないクラス
package simplex.bn25.datemasa335859.trading.stock;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class TickerManager {
private static final String CSV_FILE_PATH = "trading-app/src/stocks.csv";
private static final Set<String> EXISTING_TICKERS = new HashSet<>();
private static final Map<String, String> TICKERS_TO_NAME_MAP = new HashMap<>();
private static boolean isLoaded = false;
// 初回のみ銘柄コードと銘柄名を読み込む
public static void loadExistingTickers() {
if (isLoaded) {
return;
}
try (BufferedReader br = new BufferedReader(new FileReader(CSV_FILE_PATH))) {
br.readLine(); // ヘッダー行をスキップ
String line;
while ((line = br.readLine()) != null) {
String[] stockData = line.split(",");
if (stockData.length >= 2) { // 銘柄コードと銘柄名の両方が存在する場合のみ追加
String ticker = stockData[0].trim();
String name = stockData[1].trim();
EXISTING_TICKERS.add(ticker);
TICKERS_TO_NAME_MAP.put(ticker, name);
}
}
isLoaded = true;
} catch (IOException e) {
System.out.println("エラー: stocks.csv の読み込みに失敗しました。");
}
}
// 有効なティッカーコードのセットを取得
public static Set<String> getExistingTickers() {
if (!isLoaded) {
loadExistingTickers();
}
return EXISTING_TICKERS;
}
// 銘柄コードと銘柄名のマップを取得
public static Map<String, String> getTickerToNameMap() {
if (!isLoaded) {
loadExistingTickers();
}
return TICKERS_TO_NAME_MAP;
}
public static void addTicker(String ticker) {
EXISTING_TICKERS.add(ticker);
}
}
public BigDecimal calculateValuation(BigDecimal marketPrice) {
return marketPrice != null
? marketPrice.multiply(BigDecimal.valueOf(quantity)).setScale(2, RoundingMode.HALF_UP)
: null;
}
public BigDecimal calculateUnrealizedPnL(BigDecimal marketPrice) {
BigDecimal valuation = calculateValuation(marketPrice);
if (valuation != null) {
return valuation.subtract(averageUnitPrice.multiply(BigDecimal.valueOf(quantity)))
.setScale(2, RoundingMode.HALF_UP);
}
return null;
}
コメント