How to Apply a Fixed Equity Amount per Order

How to Apply a Fixed Equity Amount per Order

#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 PositionSizingAPI import *
from AssemblyPositionSizing_3000_ImportedScripts import *
# ---------------------------------------------------------------
#endregion

# Import the math package to gain access to the floor function.
import math

## <summary>
## Position Sizing scripts are used for overriding the quantity of pending orders after those were generated by a Trading Strategy script.
## Common use-cases include testing the impact of various position sizing methods on a trading strategy's performance, as well as sharing sophisticated position sizing logic between strategies. 
## Using Position Sizing scripts is completely optional as Trading Strategy scripts already assign quantity to all of their orders.
## </summary>
class MyPositionSizing(ScriptCode.PositionSizingScriptBase): # 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 an integer.
    ## Set to "IntegerArray" when the data type is an integer list.
    ## Set to "DateTime" when the data type is is an integer representing a date/time.
    ## Set to "DateTimeArray" when the data type is an integer list representing a list of date/time.
    ## Set to "Boolean" when the data type is a boolean.
    ## Set to "BooleanArray" when the data type is a list of booleans.
    ## Set to "Double" when the data type is a number.
    ## Set to "DoubleArray" when the data type is a list of numbers.
    ## Set to "String" when the data type is a string.
    ## Set to "StringArray" when the data type is a list of strings.

    ## 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="fixedEquityPerTrade" type="Double" default="5000">The fixed amount of equity to invest in a single trade, denominated in the account currency.</param>
    ## <param name="enableExitSizing" type="Boolean" default="True">Use to indicate whether to enable the position sizing script to determine the size of exit orders.</param>
    def OnInitialize(self,fixedEquityPerTrade,enableExitSizing):
		## Set the parameters to script variables. 
        self._fixedEquityPerTrade = fixedEquityPerTrade
        self._enableExitSizing = enableExitSizing
    #endregion
        
    #region OnPositionSize
    ## <summary>
    ## This function is called for each pending order. It should examine the specified order and 
    ## return the number of shares, contracts or units to assign it. 
    ## </summary>
    ## <param name="symbolIndex" type="Integer">The index of the symbol in the strategy symbol table</param>
    ## <param name="orderIndex" type="Integer">The order index to which a size should be assigned</param>
    ## <returns type="Double">The number of shares, contracts or units to assign the specified order.</returns>
    def OnPositionSize(self, symbolIndex, orderIndex):
        # Check if a position already exists and the script should size exit orders based on position size.
        if PositionExists(C_PositionStatus.OPEN) and self._enableExitSizing:
            # Get the indices of open positions.
            positionIndices = PositionByStatus(C_PositionStatus.OPEN)
            # Iterate through the open positions.
            for positionIndex in positionIndices:
                # Check if the current order is meant to close the open position.
                if PositionDirection(positionIndex) != OrderDirection(orderIndex):
                    # Return the current quantity of the open position.
                    return PositionCurrentQuantity(positionIndex)
        else:
            # Return the number of shares that can be traded for the provided fixed equity amount.
            return self.CalculateFE(symbolIndex)
    #endregion

    #region OnShutdown
    ## <summary>
    ## This function is called when the script is shutdown.
    ## </summary>
    def OnShutdown(self):
        # OnShutdown Content
        pass
    #endregion

    def CalculateFE(self, symbolIndex):
        # Get the latest close.
        close = DataClose(0)
        # Get the exchange rate from the symbol's currency code to the strategy's currency code.
        exchangeRate = StrategyGetExchangeRate(SymbolCurrencyCode(), StrategyCurrencyCode())
        # Check whether the bar close is valid.
        if close > 0:
            # Calculate the number of shares and round down.
            return math.floor(self._fixedEquityPerTrade / (exchangeRate * close))
        else:
            return 0