#region Namespaces
# ---------- DON'T REMOVE OR EDIT THESE LINES -------------------
# These lines are required for integrating Python with our .NET platform.
import clr
clr.AddReference("Tickblaze.Model")
import ScriptCode
from TaxSystemAPI import *
from AssemblyTaxSystem_3000_ImportedScripts import *
# ---------------------------------------------------------------
#endregion
## <summary>
## Tax system scripts are used for calculating and reducing the capital gain taxes created by the strategies.
## </summary>
class MyTaxSystem(ScriptCode.TaxSystemScriptBase): # NEVER CHANGE THE CLASS NAME
#region Variables
# Variables Content
#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>
## --------------------------------------------------------------------------------------------------
## INSTRUCTIONS - PLEASE READ CAREFULLY
## --------------------------------------------------------------------------------------------------
## 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' (The 'long' data type can only be used for date/time representation)
## Set to "DateTimeArray" when the data type is 'long[]' (The 'long' data type can only be used for date/time representation)
## 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="longTermCapitalGainsTax" type="Double" default="15">The long term (over 12 months) capital gains tax on stock profits.</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>
def OnInitialize(self, longTermCapitalGainsTax, taxMonth, taxDay):
# Set the script time zone to the local time zone.
DateTimeSetLocalZone()
# Set the parameters to script variables.
self._longTermCapitalGainsTax = longTermCapitalGainsTax
self._taxMonth = taxMonth
self._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 strategys 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>
def OnTax(self):
# Check whether the date should be skipped.
if DateTimeMonth(DateTimeCurrent()) != self._taxMonth or DateTimeDay(DateTimeCurrent()) != self._taxDay:
return
# Get the current tax year.
taxYear = DateTimeYear(DateTimeCurrent()) - 1
# Iterate over all of the strategies.
for i in range(StrategyCount()):
# Check whether the strategy isn't active.
if not StrategyIsActive(i):
continue
# The tax cost for the new strategy.
taxCost = 0
# Get the closed trades indexes for the current strategy.
closedTrades = PositionByStatus(i, C_PositionStatus.CLOSED, None)
# Iterate over all of the closed trade indexes.
for j in range(len(closedTrades)):
# Get the year in which the current trade was closed.
tradeExitYear = DateTimeYear(PositionExitDateTime(i, closedTrades[j]))
# Check whether the trade year equals to the current tax year.
if taxYear == tradeExitYear:
# Get the exchange rate from the symbol currency code to the strategy currency code.
exchangeRate = StrategyGetExchangeRate(PositionCurrencyCode(i, closedTrades[j]), StrategyCurrencyCode(i))
# Get the trade profit/loss.
PL = exchangeRate * PositionProfitLoss(i, closedTrades[j])
# Get the trade symbol index.
symbolIndex = PositionSymbolIndex(i, closedTrades[j])
# Check whether the trade is for a stock symbol.
if SymbolInstrument(i, symbolIndex) == C_Instrument.STOCK or SymbolInstrument(i, symbolIndex) == C_Instrument.ETF or SymbolInstrument(i, symbolIndex) == C_Instrument.INDEX:
# Check whether the trade was a long term trade. (More than a year).
if PositionDays(i, closedTrades[j]) > 365:
taxCost = taxCost + PL * (self._longTermCapitalGainsTax / 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 " + str(taxYear))
#endregion
#region OnShutdown
## <summary>
## This function is called when the script is shutdown.
## </summary>
def OnShutdown(self):
# OnShutdown Content
pass
#endregion