Skip to content

PythonApiCodingStyle3

OpenTrading edited this page Aug 29, 2016 · 1 revision

See PythonApiCodingStyle

Mixed Style

What's most important in Python naming is that classes start with an uppercase letter and instances or functions or variables start with a lowercase letter. This is almost a hard and fast rule.

Python used to use mixedCase naming that is in keeping with the above hard and fast rule. A mixed style that reflects the naming conventions in the C# code that Python wraps, which would make it easier to find things between the languages, is to use a simple lowercase single letter prefix and the C# name unchanged. This adheres to the hard and fast rule, and at the same time, keeps the exact link to the C# names, which is important enough that Pythonistas won't mind the lack of underscores.

It has the added advantage of us probably being able to automatically generate the Python name from the C# code with simple text tools (grep/sed/...). It also ensures that the names will never conflict with Python builtins or standard Python library names.

As a demonstration, here is a quick set of prefixes for this example.

  • ''v'' - void return type
  • ''b'' - boolean
  • ''i'' - integer
  • ''f'' - float
  • ''l'' - list or set
  • ''d'' - dictionary
  • ''s'' - string
  • ''o'' - instance of a Class
  • ''g'' - any type

(We can flesh out the list later if this one syntax is adopted.)

In the example below, I haven't really looked at the return values of most calls - someone who knows the C# code can correct me - and I may have missed some.

Overall Algorithm Structure

    def vInitialize(self):
        self.vSetStartDate(2013,10,07)   #Set Start Date
        self.vSetEndDate(2013,10,11)     #Set End Date
        self.vSetCash(100000)             #Set Strategy Cash
        self.vAddSecurity(SecurityType.iEquity, "SPY", 
            Resolution.iSecond)

    def vOnData(self, data):
        if not self.oPortfolio.bInvested:
            self.vSetHoldings("SPY", 1)

Indicators

    def vInit(self):
        self.__oMacd = None
        self.__sSymbol = "SPY"

    def Initialize(self):
        # define our daily macd(12,26) with a 9 day signal
        self.__oMacd = self.MACD(self.__sSymbol, 9, 26, 9, 
            oMovingAverageType.iExponential, oResolution.iDaily)

    def OnData(self, data):
        if not self.__oMacd.bIsReady: return    

        fTolerance = 0.0025
        holdings = self.oPortfolio[self.__sSymbol].IQuantity        

        fSignalDeltaPercent =
            (self.__oMacd.Current.Value - 
             self.__oMacd.Signal.Current.Value)/ self.__oMacd.Fast.Current.Value

        if holdings <= 0 and fSignalDeltaPercent > fTolerance:
            self.vSetHoldings(self.__sSymbol, 1.0)
        elif holdings >= 0 and fSignalDeltaPercent < -fTolerance:
            self.Liquidate(self.__sSymbol)

Universe

    def __init__(self):
        self.__iNumberOfSymbols = 5
        self.__oChanges = SecurityChanges.None

    def Initialize(self):
        self.UniverseSettings.Resolution = Resolution.Daily        
        self.AddUniverse(self.lCoarseSelectionFunction)

    def OnData(self, data):
        if self.__oChanges == SecurityChanges.None: return

        for oSecurity in self.__oChanges.RemovedSecurities:
            if oSecurity.bInvested:
                self.Liquidate(oSecurity.sSymbol)

        for oSecurity in self.__oChanges.AddedSecurities:
            self.vSetHoldings(oSecurity.sSymbol, Decimal(0.2))    

        self.__oChanges = SecurityChanges.None

    def OnSecuritiesChanged(self, oChanges):
        self.__oChanges = oChanges

    def lCoarseSelectionFunction(self, lCoarse):
        lSortedByDollarVolume = 
            sorted(lCoarse, key=lambda x: x.iDollarVolume, reverse=True) 
        top5 = lSortedByDollarVolume[:self.__iNumberOfSymbols]
        return [x.sSymbol for x in lTop5]

Order

    def __init__(self):
        self.__sSymbol = Symbol.oCreate("SPY", SecurityType.iEquity, "USA")
        self.__lOpenMarketOnOpenOrders = []

    def OnData(self, data):
        if self.bTimeIs(8, 12 + 2, 0):
            self.vLog("Submitting MarketOnOpenOrder")

            oNewOTicket = self.oMarketOnOpenOrder(self.__sSymbol, 50)
            self.__lOpenMarketOnOpenOrders.append(oNewOTicket)

        if len(self.__lOpenMarketOnOpenOrders) == 1 
            and datetime(self.Time).minute == 59:
            oTicket = self.__lOpenMarketOnOpenOrders[0]

            if oTicket.Status == OrderStatus.iFilled:
                self.__lOpenMarketOnOpenOrders = []
                return

            iQuantity = oTicket.IQuantity + 1
            self.vLog("Updating quantity  - New Quantity: {0}".format(iQuantity))

            oUpdateOrderFields = UpdateOrderFields()
            oUpdateOrderFields.iQuantity = iQuantity
            oUpdateOrderFields.Tag = "Update #{0}"
                .format(len(oTicket.UpdateRequests) + 1)
            oTicket.vUpdate(oUpdateOrderFields)

    def OnOrderEvent(self, iOrderEvent):
        iOrder = self.Transactions.GetOrderById(orderEvent.OrderId)
        self.vLog("{0}: {1}: {2}".format(self.Time, iOrder.Type, iOrderEvent))

Setter

    def Initialize(self):
        self.SetBrokerageMessageHandler(
            CustomBrokerageMessageHandler(self))

    class CustomBrokerageMessageHandler(IBrokerageMessageHandler):
        def __init__(self, oAlgo):
            self._oAlgo = oAlgo

        def handle(self, message):
            sToLog = "{0} Event: {1}".format(self._oAlgo.Time, message.Message)
            self._oAlgo.Debug(sToLog) 
            self._oAlgo.vLog(sToLog)

Clone this wiki locally