Generic Tax System

#region Namespaces
using System;
using System.IO;
using System.Linq;
#endregion

namespace ScriptCode {
	/// <summary>
	/// Tax system scripts are used for calculating and reducing the capital gain taxes created by the strategies.
	/// </summary>
	public partial class MyTaxSystem : TaxSystemScriptBase // NEVER CHANGE THE CLASS NAME 
	{
#region Variables
		// Use for stocks capital gains tax. 
		private double _stockCapitalGainsTax;
		// Use for futures capital gains tax. 
		private double _futuresCapitalGainsTax;
		// Use for FOREX capital gains tax.
		private double _FOREXCapitalGainsTax;
		// The tax month.
		private int _taxMonth;
		// The tax day.
		private int _taxDay;
#endregion

#region OnInitialize
		/// <summary>
		/// This function is used for accepting the script parameters and for initializing the script prior to all other function calls.
		/// Once the script is assigned to a desktop, its parameter values can be specified by the user and can be selected for optimization. 
		/// </summary>
		/// --------------------------------------------------------------------------------------------------
		/// PLEASE USE THE SCRIPT WIZARD (CTRL+W) TO ADD, EDIT AND REMOVE THE SCRIPT PARAMETERS
		/// --------------------------------------------------------------------------------------------------
		/// YOU MUST SET A PARAM TAG FOR EACH PARAMETER ACCEPTED BY THIS FUNCTION.
		/// ALL PARAM TAGS SHOULD BE SET IN THE 'OnInitialize' REGION, RIGHT ABOVE THE 'OnInitialize' FUNCTION.
		/// THE ORDER OF THE TAGS MUST MATCH THE ORDER OF THE ACTUAL PARAMETERS.

		/// REQUIRED ATTRIBUTES:
		/// (1) name: The exact parameter name.
		/// (2) type: The type of data to collect from the user: 
		/// Set to "Integer" when the data type is 'int'
		/// Set to "IntegerArray" when the data type is 'int[]'
		/// Set to "DateTime" when the data type is 'long'  
		/// Set to "DateTimeArray" when the data type is 'long[]'  
		/// Set to "Boolean" when the data type is 'bool'
		/// Set to "BooleanArray" when the data type is 'bool[]'
		/// Set to "Double" when the data type is 'double'
		/// Set to "DoubleArray" when the data type is 'double[]'
		/// Set to "String" when the data type is 'string'
		/// Set to "StringArray" when the data type is 'string[]'

		/// OPTIONAL ATTRIBUTES:
		/// (3) default: The default parameter value is only valid when the type is Integer, Boolean, Double, String or an API Type. 
		/// (4) min: The minimum parameter value is only valid when the type is Integer or Double.
		/// (5) max: The maximum parameter value is only valid when the type is Integer or Double.

		/// EXAMPLE: <param name="" type="" default="" min="" max="">Enter the parameter description here.</param>
		/// --------------------------------------------------------------------------------------------------
		/// <param name="stockCapitalGainsTax" type="Double" default="15">Use for stocks capital gains tax.</param>		
		/// <param name="futuresCapitalGainsTax" type="Double" default="23">Use for futures capital gains tax.</param>		
		/// <param name="FOREXCapitalGainsTax" type="Double" default="23">Use for FOREX capital gains tax.</param>		
		/// <param name="taxMonth" type="Integer" default="4" min="1" max="12">The tax month (in the local time zone).</param>		
		/// <param name="taxDay" type="Integer" default="15" min="1" max="31">The tax day (in the local time zone).</param>       
		public void OnInitialize(
			double stockCapitalGainsTax,
			double futuresCapitalGainsTax,
			double FOREXCapitalGainsTax,
			int taxMonth,
			int taxDay) {
			// Set the script time zone to the local time zone. 
			DateTimeSetLocalZone();
			// Set the parameters to script variables. 
			_stockCapitalGainsTax = stockCapitalGainsTax;
			_futuresCapitalGainsTax = futuresCapitalGainsTax;
			_FOREXCapitalGainsTax = FOREXCapitalGainsTax;
			_taxMonth = taxMonth;
			_taxDay = taxDay;
		}
#endregion

#region OnTax
		/// <summary>
		/// This function is called daily at the desktop EOD time, at which point it should calculate and reduce capital gain taxes 
		/// from the desktop strategies as needed. Since taxes are usually calculated only once a year or once a quarter it should start by checking 
		/// the current date before running any time-consuming calculations (see the Tax functions).
		/// </summary>
		public override void OnTax() {
			// The script can only be executed at the specified date. 
			if (DateTimeMonth(DateTimeCurrent()) != _taxMonth || DateTimeDay(DateTimeCurrent()) != _taxDay)
				return ;

			// Use for holding the closed trades indexes. 
			int[] closedTrades = null;
			// The current position symbol index. 
			int symbolIndex = 0;
			// The current year tax amount. 
			double taxCost = 0;
			// The current position P/L. 
			double PL = 0;
			// Get for the current tax year. 
			int taxYear = DateTimeYear(DateTimeCurrent()) - 1;
			// Iterate over the strategies.
			for (int i = 0; i < StrategyCount(); i++) {
				// Check whether the strategy isn't active.
				if (!StrategyIsActive(i))
					continue ;

				// Reset the tax cost for the new strategy.
				taxCost = 0;
				// Get the closed positions indexes for the current strategy. 
				closedTrades = PositionByStatus(i, C_PositionStatus.CLOSED);
				// Iterate over all of the closed position indexes. 
				for (int j = 0; j < closedTrades.Length; j++) {
					// Get the year in which the current position was closed. 
					int tradeExitYear = DateTimeYear(PositionExitDateTime(i, closedTrades[j]));
					// Check whether the position year equals to the current tax year.
					if (taxYear == tradeExitYear) {
						// Get the exchange rate from the symbol currency code to the strategy currency code.
						double exchangeRate = StrategyGetExchangeRate(PositionCurrencyCode(i, closedTrades[j]), StrategyCurrencyCode(i));
						// Get the position profit/loss denominated in the strategy currency code. 
						PL = exchangeRate * PositionProfitLoss(i, closedTrades[j]);
						// Get the position symbol index. 
						symbolIndex = PositionSymbolIndex(i, closedTrades[j]);
						// Check whether the position is for a stock symbol..
						if (SymbolInstrument(i, symbolIndex) == C_Instrument.STOCK ||
							SymbolInstrument(i, symbolIndex) == C_Instrument.ETF ||
							SymbolInstrument(i, symbolIndex) == C_Instrument.INDEX) {
							taxCost = taxCost + PL * (_stockCapitalGainsTax / 100);
						}
						// Check whether the position is for a futures/CFD symbol.
						else if (SymbolInstrument(i, symbolIndex) == C_Instrument.FUTURE ||
								 SymbolInstrument(i, symbolIndex) == C_Instrument.CFD) {
							taxCost = taxCost + PL * (_futuresCapitalGainsTax / 100);
						}
						// Check whether the position is for a FOREX symbol.
						else if (SymbolInstrument(i, symbolIndex) == C_Instrument.FOREX) {
							taxCost = taxCost + PL * (_FOREXCapitalGainsTax / 100);
						}
					}
				}
				// Check whether there were taxes to be paid.
				if (taxCost > 0) {
					// Pay the taxes.
					TaxPay(i, taxCost, "Taxes paid for the tax year of " + taxYear);
				}
				else {
					// Don't pay taxes.
					TaxPay(i, 0, "Zero capital gains for the tax year of " + taxYear);
				}
			}
		}
#endregion

#region OnShutdown
		/// <summary>
		/// This function is called when the script is shutdown.
		/// </summary>
		public override void OnShutdown() {

		}
#endregion
	}
}