コメント

package simplex.bn25.makino335926.trading.position;

import simplex.bn25.makino335926.trading.trade.Trade;

import java.math.BigDecimal;
import java.util.*;

/**
 * クラス: PositionCalculator
 * 取引(Trade)データをもとに、各銘柄のポジションを計算するクラス。
 * 保有数量、平均取得単価、実現損益、評価額などを計算し、最終的なポジションリストを生成する。
 */
public class PositionCalculator {

    /**
     * メソッド: calculatePositions
     * 与えられた取引データと時価データをもとに、銘柄ごとのポジションを計算。
     *
     * @param trades       List<Trade> 取引データのリスト
     * @param marketPrices Map<String, BigDecimal> 各銘柄コードに対応する時価情報
     * @return List<Position> 計算済みのポジションリスト(銘柄コード順にソート済み)
     */
    public static List<Position> calculatePositions(List<Trade> trades, Map<String, BigDecimal> marketPrices) {
        // 銘柄コードをキーとするポジションデータを格納するマップ
        Map<String, Position> positions = new HashMap<>();

        // 1. 取引データを順に処理し、ポジションを更新
        for (Trade trade : trades) {
            // 現在処理中の取引の銘柄コードを取得
            String ticker = trade.ticker();

            // マップに該当銘柄のポジションがなければ、新規作成して追加
            positions.putIfAbsent(ticker, new Position(ticker, trade.name()));

            // 該当銘柄のポジションオブジェクトを取得
            Position position = positions.get(ticker);

            // 取引区分(BUYまたはSELL)に応じた処理を行う
            if (trade.side().equals("BUY")) {
                // 買い取引の場合、平均取得単価を更新
                // 新規取得した単価(tradedUnitPrice)と数量(quantity)を加重平均計算に使用
                position.updateAverageUnitPrice(trade.tradedUnitPrice(), trade.quantity());
            } else if (trade.side().equals("SELL")) {
                // 売り取引の場合、次の計算を行う:
                // 1. 損益(P/L: Profit or Loss)を計算
                // 売却単価(tradedUnitPrice) - 平均取得単価 × 売却数量(quantity)
                BigDecimal pnl = trade.tradedUnitPrice().subtract(position.getAverageUnitPrice())
                        .multiply(BigDecimal.valueOf(trade.quantity()));

                // 2. 実現損益を更新
                position.addRealizedPnL(pnl);

                // 3. 保有数量を減少
                position.updateQuantity(-trade.quantity());
            }
        }

        // 2. 全ての銘柄の評価額を計算
        for (Position position : positions.values()) {
            // マーケット価格を取得し、ポジションの評価額を設定
            // 時価情報が存在しない場合は評価額は設定されない(nullのまま)
            position.setValuation(marketPrices.get(position.getTicker()));
        }

        // 3. マップをリストに変換し、銘柄コード順にソート
        List<Position> positionList = new ArrayList<>(positions.values());
        positionList.sort(Comparator.comparing(Position::getTicker));

        // 計算されたポジションリストを返す
        return positionList;
    }
}

コメント

タイトルとURLをコピーしました