Custom Trading Indicators Development

Define user-authored indicator calculations in Python for supported Investfly workflows.

Investfly exposes a catalog of standard technical indicators. These built-in indicators can be referenced in user-authored algorithmic trading strategies and can be utilized in screeners, automated trade signals, and backtesting engines.

You can implement custom calculations in Python and use them in supported workflows. Availability, data, execution limits, and compatibility depend on the current platform and workflow. A custom indicator is not a recommendation and does not predict market movements or strategy results.

Developer Requirement

This guide assumes proficiency with Python programming and object-oriented concepts for developing algorithmic trading indicators.

Algorithmic Trading Indicator Architecture

Indicator Base Class

The Indicator class provides the foundational framework for creating any type of technical indicator for algorithmic trading. Its flexible design accommodates indicators based on various data inputs, including price action, volume patterns, market sentiment, or alternative data sources.

While we provide the SecurityDataProvider class for historical market data access, advanced algorithmic traders can incorporate external data sources using Python's requests module to create indicators based on unique datasets like social media sentiment, options flow, or macroeconomic indicators.

To develop a proprietary trading indicator, extend the Indicator base class and implement these required methods:

@abstractmethod def getIndicatorSpec(self) -> IndicatorSpec: # Return IndicatorDefinition with name, description, required params, and valuetype # See IndicatorSpec abstract class for more details pass @abstractmethod def computeSeries(self, params: Dict[str, Any], bars: List[Bar]) -> List[DatedValue]: # This is the main function which must compute and return value. This function must return within 1 sec # or it will be killed pass

IndicatorSpec Class

The IndicatorSpec class defines the metadata for your custom algorithmic trading indicator, including its name, description, required parameters, and output value type. This specification serves as the blueprint for how your indicator will be presented and used throughout the Investfly platform.

When implementing the getIndicatorSpec method, you must return an instance of IndicatorSpec with all required metadata properly defined:

def getIndicatorSpec(self) -> IndicatorSpec: spec = IndicatorSpec() spec.name = "Custom RSI Divergence" # Name displayed in the platform spec.description = "Detects divergence between price and RSI" # User-friendly description # Define the parameters your indicator requires lengthParam = IntegerParameterDefinition() lengthParam.name = "length" lengthParam.description = "Look-back period for RSI calculation" lengthParam.defaultValue = 14 lengthParam.minValue = 2 lengthParam.maxValue = 100 spec.parameters.append(lengthParam) # Specify the type of value your indicator returns spec.valueType = ValueType.BOOLEAN # For signals that return true/false # Other options: NUMERIC (for values), ENUM (for categorical values) return spec

Python Restrictions

Your custom indicator code runs in a restricted and sandboxed Python environment for security reasons. This ensures that the code cannot perform any malicious tasks on our servers. Only a few white-listed safe modules can be imported. System operations such as file IO are not allowed, and wildcard imports are also restricted.

If you find any safe function that is blocked, please contact us, and we can make it available.

Allowed Python Modules

  • numpy
  • pandas
  • datetime
  • math
  • statistics
  • random
  • requests (limited)
  • json
  • collections

Computing Algorithmic Trading Signals

The core functionality of your custom indicator is implemented in the computeSeries method. This method receives historical price data and your indicator's parameters, and must return a series of dated values representing your indicator's calculations.

Keep calculations within the execution limits documented by the current platform. Data timing, system load, and execution limits can affect evaluation.

Example: Simple Moving Average Crossover Signal

Below is a complete example of a custom indicator that generates buy signals when a fast moving average crosses above a slow moving average:

from typing import Dict, List, Any from datetime import datetime import numpy as np class MACrossoverSignal(Indicator): def getIndicatorSpec(self) -> IndicatorSpec: spec = IndicatorSpec() spec.name = "MA Crossover Signal" spec.description = "Generates buy signal when fast MA crosses above slow MA" # Fast MA period parameter fastParam = IntegerParameterDefinition() fastParam.name = "fastPeriod" fastParam.description = "Fast moving average period" fastParam.defaultValue = 5 fastParam.minValue = 2 fastParam.maxValue = 50 spec.parameters.append(fastParam) # Slow MA period parameter slowParam = IntegerParameterDefinition() slowParam.name = "slowPeriod" slowParam.description = "Slow moving average period" slowParam.defaultValue = 20 slowParam.minValue = 5 slowParam.maxValue = 200 spec.parameters.append(slowParam) # Return boolean values (true for buy signal, false for no signal) spec.valueType = ValueType.BOOLEAN return spec def computeSeries(self, params: Dict[str, Any], bars: List[Bar]) -> List[DatedValue]: # Extract parameters fast_period = params["fastPeriod"] slow_period = params["slowPeriod"] # Extract closing prices from bars closes = [bar.close for bar in bars] # Calculate moving averages fast_ma = self._calculate_sma(closes, fast_period) slow_ma = self._calculate_sma(closes, slow_period) # Generate signals when fast MA crosses above slow MA result = [] for i in range(len(bars)): if i < slow_period: # Not enough data for both MAs signal = False elif i == slow_period: # First point where we have both MAs, no previous point to compare signal = False else: # Check for crossover: fast MA was below slow MA yesterday and is above today yesterday_fast_above_slow = fast_ma[i-1] > slow_ma[i-1] today_fast_above_slow = fast_ma[i] > slow_ma[i] signal = not yesterday_fast_above_slow and today_fast_above_slow # Add result with date from bar result.append(DatedValue(bars[i].date, signal)) return result def _calculate_sma(self, values, period): # Using numpy for efficient calculation result = np.zeros(len(values)) for i in range(len(values)): if i < period - 1: result[i]=float('nan') # Not enough data else: result[i] = sum(values[i-(period-1):i+1]) / period return result

Deploying Custom Indicators to Your Algorithmic Trading Platform

After defining your custom indicator class, you need to register it with Investfly's platform to make it available for use in your trading strategies, screeners, and charts.

Custom Indicator Registration

Navigate to User Settings > Custom Indicators in the Investfly platform. Paste your Python code into the editor and click "Save & Compile". Once successfully validated, your custom indicator will be available throughout the platform alongside standard indicators.

Custom Algorithmic Trading Indicator Editor

After deployment, your custom algorithmic trading indicator can be:

  • Used in trading strategy conditions to generate automated trade signals
  • Displayed on price charts for technical analysis
  • Incorporated into stock screeners to find securities matching specific patterns
  • Used in backtesting to evaluate historical performance
  • Combined with other indicators to create complex algorithmic trading rules

Indicator Implementation Practices

When developing custom indicators for algorithmic trading strategies, consider these best practices:

Performance Optimization

Optimize your code for speed using vectorized operations with NumPy whenever possible. The platform imposes a 1-second execution limit to maintain responsiveness during live trading.

Error Handling

Implement robust error handling to manage edge cases like insufficient data points or unexpected input values. Return appropriate fallback values when calculations cannot be performed.

Avoid Look-Ahead Bias

Ensure your indicator only uses data that would have been available at each historical point to prevent unrealistic backtesting results and false trade signals.

Thorough Testing

Extensively backtest your custom indicators across different market conditions and timeframes to validate their reliability before using them in live algorithmic trading.

Review Before Use

Test custom calculations, handle missing or unexpected data, and review every strategy rule that references the indicator. Historical and simulated results do not predict live results.

Ready to Get Started?

Start automating your trading strategies today with our free 14-day trial.

Start Free Trial

No credit card required.