/*
 * Copyright (c) 2006-2009 OrangeSignal.com All rights reserved.
 * 
 * これは Apache ライセンス Version 2.0 (以下、このライセンスと記述) に
 * 従っています。このライセンスに準拠する場合以外、このファイルを使用
 * してはなりません。このライセンスのコピーは以下から入手できます。
 * 
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 * 
 * 適用可能な法律がある、あるいは文書によって明記されている場合を除き、
 * このライセンスの下で配布されているソフトウェアは、明示的であるか暗黙の
 * うちであるかを問わず、「保証やあらゆる種類の条件を含んでおらず」、
 * 「あるがまま」の状態で提供されるものとします。
 * このライセンスが適用される特定の許諾と制限については、このライセンス
 * を参照してください。
 */

package jp.sf.orangesignal.trading.stats;

import java.util.Date;
import java.util.LinkedList;

import jp.sf.orangesignal.trading.Position;
import jp.sf.orangesignal.trading.PositionType;
import jp.sf.orangesignal.trading.data.Dataset;
import jp.sf.orangesignal.trading.data.IntervalType;

/**
 * <p>パフォーマンス統計情報を提供します。</p>
 * 
 * @author 杉澤 浩二
 */
public class Stats extends WinLossStats {

	private static final long serialVersionUID = 1L;

	/**
	 * <p>デフォルトコンストラクタです。</p>
	 * <p>このコンストラクタはサブクラスを実装する開発者向けに提供しています。</p>
	 */
	protected Stats() {}

	/**
	 * ポジション情報のリストと初期資金を指定してこのクラクを構築するコンストラクタです。
	 * 
	 * @param positions ポジション情報のリスト
	 * @param initialCapital 初期資金
	 */
	public Stats(final LinkedList<Position> positions, final double initialCapital) {
		statistics(positions, initialCapital, false);
	}

	/**
	 * ポジション情報のリストと初期資金を指定してこのクラクを構築するコンストラクタです。
	 * 
	 * @param positions ポジション情報のリスト
	 * @param initialCapital 初期資金
	 * @param dataset データセット
	 * @param start 検証開始日時
	 * @param end 検証終了日時
	 */
	public Stats(
			final LinkedList<Position> positions,
			final double initialCapital,
			final Dataset dataset,
			final int start,
			final int end)
	{
		statistics(positions, initialCapital, false);
		if (dataset != null)
			statistics(dataset, start, end);
	}

	// ----------------------------------------------------------------------

	@Override
	protected void statistics(final LinkedList<Position> positions, final double initialCapital, final boolean discard) {
		super.statistics(positions, initialCapital, discard);

		final AbstractStats parent = this;
		longStats = new WinLossStats(positions, initialCapital, true) {
			private static final long serialVersionUID = 1L;
			@Override protected boolean isStatistics(final Position p) {
				return parent.isStatistics(p) && p.getType() == PositionType.LONG;
			}
		};
		shortStats = new WinLossStats(positions, initialCapital, true) {
			private static final long serialVersionUID = 1L;
			@Override protected boolean isStatistics(final Position p) {
				return parent.isStatistics(p) && p.getType() == PositionType.SHORT;
			}
		};
	}

	/**
	 * <p>指定されたデータセットを解析して、このクラスの統計情報を設定します。</p>
	 * 
	 * @param dataset データセット
	 * @param start 検証開始日時
	 * @param end 検証終了日時
	 */
	protected void statistics(final Dataset dataset, final int start, final int end) {
		if (start < 0 || end < 0 || start > end)
			throw new IllegalArgumentException();
		this.symbol = dataset.getSymbol();
		this.symbolName = dataset.getSymbolName();
		this.startDate = dataset.getDate()[start];
		this.endDate = dataset.getDate()[end];
		this.period = end - start + 1;
		this.interval = dataset.getInterval();
	}

	/**
	 * この実装は指定されたポジションが閉じられている場合は <code>true</code> を、それ以外の場合は <code>false</code> を返します。
	 */
	@Override protected boolean isStatistics(final Position p) { return p.isClosed(); }

	// ----------------------------------------------------------------------

	/**
	 * シンボルを保持します。
	 */
	protected String symbol;

	/**
	 * シンボルを返します。
	 * 
	 * @return シンボル。又は <code>null</code>
	 */
	public String getSymbol() { return symbol; }

	/**
	 * シンボル名を保持します。
	 */
	protected String symbolName;

	/**
	 * シンボル名を返します。
	 * 
	 * @return シンボル名。又は <code>null</code>
	 */
	public String getSymbolName() { return symbolName; }

	/**
	 * 開始日時を保持します。
	 */
	protected Date startDate;

	/**
	 * 開始日時を返します。
	 * 
	 * @return 開始日時。又は <code>null</code>
	 */
	public Date getStartDate() { return startDate; }

	/**
	 * 終了日時を保持します。
	 */
	protected Date endDate;

	/**
	 * 終了日時を返します。
	 * 
	 * @return 終了日時。又は <code>null</code>
	 */
	public Date getEndDate() { return endDate; }

	/**
	 * データの数を保持します。
	 */
	protected int period;

	/**
	 * 期間率を返します。
	 * 
	 * @return 期間率
	 */
	public double getPercentHold() {
		if (hold == 0 || period == 0)
			return 0;
		return (double) hold / (double) period;
	}

	/**
	 * 買い期間率を返します。
	 * 
	 * @return 買い期間率
	 */
	public double getPercentLongHold() {
		if (longStats.hold == 0 || period == 0)
			return 0;
		return (double) winStats.hold / (double) period;
	}

	/**
	 * 売り期間率を返します。
	 * 
	 * @return 売り期間率
	 */
	public double getPercentShortHold() {
		if (shortStats.hold == 0 || period == 0)
			return 0;
		return (double) lossStats.hold / (double) period;
	}

	/**
	 * データの数を返します。
	 * 
	 * @return データの数
	 */
	public int getPeriod() { return period; }

	/**
	 * データの足単位を保持します。
	 */
	private IntervalType interval;

	/**
	 * データの足単位を返します。
	 * 
	 * @return データの足単位
	 */
	public IntervalType getInterval() { return interval; }

	// ----------------------------------------------------------------------

	/**
	 * 買いトレードのパフォーマンス統計情報を保持します。
	 */
	protected WinLossStats longStats;

	/**
	 * 買いトレードのパフォーマンス統計情報を返します。
	 * 
	 * @return 買いトレードのパフォーマンス統計情報
	 */
	public WinLossStats getLongStats() { return longStats; }

	/**
	 * 売りトレードのパフォーマンス統計情報を保持します。
	 */
	protected WinLossStats shortStats;

	/**
	 * 売りトレードのパフォーマンス統計情報を返します。
	 * 
	 * @return 売りトレードのパフォーマンス統計情報
	 */
	public WinLossStats getShortStats() { return shortStats; }

	// ----------------------------------------------------------------------

	/**
	 * <p>買いトレード数を返します。</p>
	 * <p>このメソッドは利便性の為に提供しています。</p>
	 * 
	 * @return 買いトレード数
	 */
	public int getLongTrades() { return getLongStats().getCount(); }

	/**
	 * <p>売りトレード数を返します。</p>
	 * <p>このメソッドは利便性の為に提供しています。</p>
	 * 
	 * @return 売りトレード数
	 */
	public int getShortTrades() { return getShortStats().getCount(); }

}
