# Alert Limitations, Delivery, and History
Source: https://takeprofit.com/docs/guide/alerts/Alert-limitations-delivery-history
### Alert Limits
* Free users can create 1 alert with up to 3 months expiration
* Premium users can create up to 50 alerts with extended expiration periods
* All alerts remain active as long as the user maintains premium status
### Notifications Limits
* Real-time platform updates are limited to 10 times per second
* On-platform notifications have no delivery limitations
* Email notifications are limited to once per minute per email address
* Webhook notifications are subject to rate limiting (limits are being adjusted and will be updated soon).
### Alert History

* Complete trigger history is available in the platform's alerts log
* Alert history is maintained for the entire lifetime of the alert
* Alert logs are automatically removed when the corresponding alert is deleted.
# Alert Trigger Criteria
Source: https://takeprofit.com/docs/guide/alerts/Alert-trigger-criteria
This guide provides a detailed description of the various alert trigger criteria available in the **TakeProfit** platform. Understanding these criteria will help you set up alerts that align with your trading strategies and preferences, allowing you to respond promptly to market changes.

## Introduction
Alerts are an important tool for traders, allowing them to respond promptly to market changes. In **TakeProfit**, you can set up alerts with various trigger criteria tailored to your trading strategies. This guide will help you understand and effectively use these criteria, providing examples involving cryptocurrencies, stocks, and technical indicators.
List of availbale criteria:
The trigger activates when the price or indicator value increases by a
specified amount.
The trigger activates when the price or indicator value decreases by a
specified amount.
The trigger activates when the price or indicator value increases by a
specified percentage.
The trigger activates when the price or indicator value decreases by a
specified percentage.
The trigger activates when two data series cross at any point.
The trigger activates when one data series crosses another from below.
The trigger activates when one data series crosses another from above.
The trigger activates when the price or indicator value exceeds a specified
value.
The trigger activates when the price or indicator value falls below a
specified value.
The trigger activates when the price or indicator value enters a specified
range.
The trigger activates when the price or indicator value exits a specified
range.
The trigger activates as long as the price or indicator value remains within
a specified range.
The trigger activates when the price or indicator value is outside a
specified range.
***
## Moving Up
**Description:**
The trigger activates when an asset's price or indicator value increases by a specified amount within a certain number of bars.
**Usage:**
* Monitoring significant increases in price or indicator over a short period.
* Identifying the start of an upward trend.
* Tracking strong bullish momentum.
**Examples:**
| Asset | Condition |
| -------------------- | --------------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when the price of **Apple (AAPL)** increases by **5** over the last **3 hours**. |
| **Cryptocurrencies** | Notify when **Bitcoin (BTC)** rises by **1,000** within the last **2 hours**. |
| **Indicators** | Notify when the **RSI** value increases by **10 points** over the last **5 bars**, indicating strengthening momentum. |
**Tips:**
* Adjust the amount of change according to the asset's volatility.
* Use to spot entry opportunities in a rising market.
* When monitoring indicators, pay attention to significant shifts that may signal a trend change.
***
## Moving Down
**Description:**
The trigger activates when an asset's price or indicator value decreases by a specified amount within a certain number of bars.
**Usage:**
* Monitoring sharp declines in price or indicator.
* Identifying the start of a downward trend or buying opportunities during a pullback.
* Monitoring weakening market momentum.
**Examples:**
| Asset | Condition |
| -------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when the price of **Tesla (TSLA)** decreases by **10** over the last **4 hours**. |
| **Cryptocurrencies** | Notify when **Ethereum (ETH)** drops by **200** within the last **6 hours**. |
| **Indicators** | Notify when the **MACD** value decreases by **5 points** over the last **3 bars**, indicating weakening momentum. |
**Tips:**
* Helps in timely decision-making for exiting positions or entering at a better level.
* Combine with volume analysis to confirm the strength of the movement.
* When monitoring indicators, track declines that may precede price reversals.
***
## Moving Up %
**Description:**
The trigger activates when an asset's price or indicator value increases by a specified percentage over a defined period.
**Usage:**
* Monitoring significant percentage gains.
* Identifying assets or indicators with strong upward momentum.
* Tracking market dynamics.
**Examples:**
| Asset | Condition |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when **Netflix (NFLX)** shares rise by **5%** over the last **2 days**. |
| **Cryptocurrencies** | Notify when **Ripple (XRP)** increases by **10%** within the last **24 hours**. |
| **Indicators** | Notify when the **On-Balance Volume (OBV)** increases by **8%** over the last **10 bars**, indicating strong buying pressure. |
**Tips:**
* Percentage changes are convenient for comparing assets with different price levels.
* Useful when screening the market for assets or indicators showing strong momentum.
* Apply to percentage-based indicators for consistent analysis.
***
## Moving Down %
**Description:**
The trigger activates when an asset's price or indicator value decreases by a specified percentage over a defined period.
**Usage:**
* Monitoring significant percentage declines.
* Identifying buying opportunities after a price correction.
* Monitoring weakening indicators that may precede a reversal.
**Examples:**
| Asset | Condition |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Stocks** | Notify when **Amazon (AMZN)** shares fall by **8%** over the last **3 days**. |
| **Cryptocurrencies** | Notify when **Litecoin (LTC)** decreases by **15%** within the last **12 hours**. |
| **Indicators** | Notify when the **Stochastic Oscillator** decreases by **20%** over the last **5 bars**, indicating approaching oversold conditions. |
**Tips:**
* Helps identify oversold assets or weakening indicators.
* Combine with technical analysis for signal confirmation.
* Monitoring indicator declines can help anticipate potential reversals.
***
## Crossing
**Description:**
The trigger activates when two data series cross at any point.
**Usage:**
* Identifying potential trend reversals.
* Monitoring crossovers between moving averages or indicators.
* Detecting significant market signals.
**Examples:**
| Asset | Condition |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **Indicators** | Notify when the **50-day SMA** crosses the **200-day SMA** on **Google (GOOGL)** chart (Golden Cross or Death Cross). |
| **Cryptocurrencies** | Notify when the **MACD line** crosses the **signal line** on **Bitcoin (BTC)** chart, signaling a potential change in momentum. |
| **Stocks** | Notify when the **Price** crosses the **Ichimoku Cloud** on **NVIDIA (NVDA)** chart, indicating a potential trend change. |
**Tips:**
* Crossovers of moving averages or indicators can signal significant market shifts.
* Use in combination with other technical tools to confirm signals.
* Be aware of false signals in volatile markets.
***
## Cross Up
**Description:**
The trigger activates when one data series crosses another from below.
**Usage:**
* Signals a possible start of an upward trend.
* Identifying bullish signals.
* Monitoring increasing market momentum.
**Examples:**
| Asset | Condition |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when the price of **Microsoft (MSFT)** crosses above the **100-day SMA** from below, indicating a bullish trend. |
| **Indicators** | Notify when the **RSI** crosses above the **30** level on **Ethereum (ETH)** chart, indicating exit from the oversold zone. |
| **Cryptocurrencies** | Notify when the **Chaikin Money Flow (CMF)** crosses above zero on **Cardano (ADA)** chart, suggesting increasing buying pressure. |
**Tips:**
* Cross Up is often considered a buy signal.
* Confirm signals with volume and other indicators for increased reliability.
* Consider the context and overall market conditions.
***
## Cross Down
**Description:**
The trigger activates when one data series crosses another from above.
**Usage:**
* Signals a possible start of a downward trend.
* Identifying bearish signals.
* Monitoring decreasing market momentum.
**Examples:**
| Asset | Condition |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when the price of **Facebook (FB)** crosses below the **50-day SMA** from above, indicating potential weakness. |
| **Indicators** | Notify when the **RSI** crosses below the **70** level on **Litecoin (LTC)** chart, indicating exit from the overbought zone. |
| **Cryptocurrencies** | Notify when the **MACD line** crosses below the **signal line** on **Bitcoin Cash (BCH)** chart, signaling a potential bearish reversal. |
**Tips:**
* Cross Down can serve as a signal to sell or close long positions.
* Use stop-loss orders to manage risks when trading on these signals.
* Consider the timeframe to filter out short-term noise.
***
## Greater Than
**Description:**
The trigger activates when the price or indicator value exceeds a specified value or another data series.
**Usage:**
* Monitoring breakouts above key resistance levels.
* Identifying the start of bullish movement.
* Tracking extreme indicator values.
**Examples:**
| Asset | Condition |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when **Tesla (TSLA)** exceeds **800**, indicating a potential breakout. |
| **Cryptocurrencies** | Notify when **Bitcoin (BTC)** surpasses its all-time high, signaling strong bullish sentiment. |
| **Indicators** | Notify when the **RSI** on **Apple (AAPL)** exceeds **70**, entering overbought territory. |
**Tips:**
* Useful for setting price targets and automating notifications when key levels are reached.
* Combine with volume analysis to confirm breakouts.
* For indicators, be cautious as overbought conditions may precede reversals.
***
## Lower Than
**Description:**
The trigger activates when the price or indicator value falls below a specified value or another data series.
**Usage:**
* Monitoring breakdowns below support levels.
* Identifying the start of bearish movement.
* Tracking extreme low indicator values.
**Examples:**
| Asset | Condition |
| -------------------- | --------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when **Netflix (NFLX)** drops below **500**, possibly indicating further downside. |
| **Cryptocurrencies** | Notify when **Ethereum (ETH)** falls below **2,000**, breaking a key support level. |
| **Indicators** | Notify when the **RSI** on **Amazon (AMZN)** drops below **30**, entering oversold territory. |
**Tips:**
* Helps react promptly to price declines and make decisions about exiting positions.
* Can be used to set stop-loss levels or identify buying opportunities.
* For indicators, oversold conditions may suggest potential rebounds.
***
## Entering Channel
**Description:**
The trigger activates when the price or indicator value enters a specified range between upper and lower boundaries.
**Usage:**
* Monitoring price consolidation within a certain range.
* Preparing for range-bound trading strategies.
* Tracking reduced volatility.
**Examples:**
| Asset | Condition |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when **Apple (AAPL)** enters the price range between **130** and **135**, indicating consolidation. |
| **Cryptocurrencies** | Notify when **Bitcoin (BTC)** enters the Bollinger Bands after being outside, suggesting reduced volatility. |
| **Indicators** | Notify when the **ADX (Average Directional Index)** on **Tesla (TSLA)** enters the range between **20** and **25**, indicating a non-trending market. |
**Tips:**
* Use to monitor sideways markets and plan trades within the range.
* Combine with other indicators to assess potential breakouts.
* Be prepared for increased volatility when exiting the channel.
***
## Exiting Channel
**Description:**
The trigger activates when the price or indicator value exits a specified range.
**Usage:**
* Identifying breakouts upwards or downwards.
* Signaling the start of a new trend or increased volatility.
* Monitoring significant market changes.
**Examples:**
| Asset | Condition |
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Notify when **Tesla (TSLA)** breaks out of the **700** - **750** price range. |
| **Cryptocurrencies** | Notify when **Ethereum (ETH)** moves outside the Keltner Channel, indicating a potential trend change. |
| **Indicators** | Notify when the **Volatility Index (VIX)** exits a low volatility range, signaling potential market turbulence. |
**Tips:**
* Breaking out of a channel may indicate the start of a significant movement.
* Confirm breakouts using volume and other technical indicators.
* Be cautious of false breakouts; consider waiting for confirmation.
***
## Inside Channel
**Description:**
The trigger activates as long as the price or indicator value remains within a specified range.
**Usage:**
* Monitoring stable periods for trading within the range.
* Tracking assets or indicators during consolidation phases.
* Planning entry and exit strategies.
**Examples:**
| Asset | Condition |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Continuously notify while **Microsoft (MSFT)** trades between **250** and **260**. |
| **Cryptocurrencies** | Notify while **Bitcoin (BTC)** is within the **45,000** - **50,000** range. |
| **Indicators** | Notify when the **Stochastic Oscillator** on **Ethereum (ETH)** remains between **40** and **60**, indicating neutrality. |
**Tips:**
* Useful for range-bound trading strategies.
* Be vigilant for signs of an impending breakout.
* Adjust range boundaries as market conditions change.
***
## Outside Channel
**Description:**
The trigger activates when the price or indicator value is outside a specified range.
**Usage:**
* Monitoring extreme price levels or indicator readings.
* Identifying assets with increased volatility or trend strength.
* Tracking significant market events.
**Examples:**
| Asset | Condition |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **Stocks** | Notify if **Facebook (FB)** trades above **350** or below **300**, indicating significant movement. |
| **Cryptocurrencies** | Notify if **Ripple (XRP)** moves outside the Bollinger Bands, suggesting increased volatility. |
| **Indicators** | Notify when the **RSI** on **Litecoin (LTC)** is above **70** or below **30**, indicating overbought or oversold conditions. |
**Tips:**
* Helps react promptly to significant market events.
* Combine with news analysis to understand underlying causes.
* For indicators, extreme values may precede reversals.
***
## Best Practices
Understand exactly what you want to monitor and why. Set up alerts according
to your trading strategy.
Avoid notification overload. Focus on the most important criteria for you.
Confirm signals using technical indicators and fundamental analysis.
Adjust criteria in line with changing market conditions. Analyze alert
effectiveness and make necessary changes.
Choose time intervals that match your trading style (day trading, swing
trading, long-term investing).
Set up alert delivery methods (mobile app, email, messengers) for quick
response.
Start with small thresholds to ensure alerts are working correctly. Adjust
parameters based on results.
Keep an eye on market news that may affect your alerts. Be aware of
scheduled events like earnings reports or economic data releases.
***
## Conclusion
Effectively using the various alert trigger criteria in the **TakeProfit** platform allows you to stay ahead in dynamic markets. By understanding and correctly applying these criteria, you can tailor alerts to your specific trading strategies, helping you make timely and informed decisions.
Remember, the key to successful alert management is continuous learning and
adaptation. Regularly refine your alerts based on market changes and personal
experience to optimize your trading outcomes.
***
> **Note:** Always consider the individual characteristics of the assets and indicators you work with, as well as the current market environment when setting up alerts. This will enhance the relevance and effectiveness of your notifications.
# Alerts overview
Source: https://takeprofit.com/docs/guide/alerts/Alerts-overview
TakeProfit alerts notify you when market conditions meet your custom criteria. Set up notifications for price movements, indicator conditions, or custom indicators you've developed.
## Alert Types and Sources
Currently available:
* Price-based alerts
* Indicator-based alerts (for any indicator on your chart)
* Custom indicator alerts (for your own indicators)
## How to Set Up Alerts
There are two ways to set up alerts in TakeProfit platform: directly on the chart or through the Alerts dialog window.
### Setting up alerts through the Alerts dialog window:

1. Click the "Alerts" button in the top right corner of your workspace
2. Click "New Alert"
3. In the dialog window, configure the following basic parameters:
* **Source**: Choose between Price or Indicator (if available on the chart)
* **Criteria**: Select the conditions that will trigger the alert
* **Target**: Enter the specific value (price level or indicator parameter)
* Click "**Add more**" to create multiple alerts simultaneously in the same window
### Setting up alerts directly on the chart:
There are several ways to create alerts right from the chart.
1. You can click the bell icon that appears when hovering over the chart - this will automatically use the current price or indicator value

2. You can also create alerts through the chart's context menu (right click)

## Additional settings
Additional settings are available under the "Expand" dropdown:
* Frequency settings
* Expiration date
* Email address for notifications
* Webhook URL for automated integrations.

# Discord Notifications
Source: https://takeprofit.com/docs/guide/alerts/Discord-webhook
This guide will help you configure automatic notifications from the **TakeProfit** platform to **Discord** using Webhook. This will allow you to receive timely alerts directly on your Discord server, enhancing your work efficiency.
## Creating a Webhook in Discord
### For a Server
1. **Open Discord** and log into your server.
2. **Go to server settings:**
* Click on the server name in the top-left corner.
* Select **"Server Settings"**.
3. **Choose the channel for notifications:**
* In the left menu, select **"Integrations"**.
* Click on **"Webhooks"**.
4. **Create a new Webhook:**
* Click **"Create Webhook"**.
* Set a **Webhook name** (e.g., "TakeProfit Alerts").
* Choose the **channel** where messages will be sent.
* **Copy the Webhook URL**—you will need it for the setup in TakeProfit.
* Click **"Save Changes"**.
***
## Configuring Webhook in TakeProfit
### Preparing the Webhook URL
* Use the Webhook URL obtained from Discord in the previous step.
* Example Webhook URL:
```URL
https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz
```
### Setting Up the Payload
1. **Log in** to your **TakeProfit** account.
2. **Create a new alert** or edit an existing one.
3. **Configure the alert conditions:**
* Specify the required parameters: **ticker**, **exchange**, **trigger condition**, etc.
4. **Add the Webhook:**
* In the notifications section, select the **Webhook URL** option.
* **Paste the Webhook URL** from Discord into the appropriate field.
5. **Set up the Payload:**
* In the **Message** field, enter the JSON with the necessary parameters.
***
## Forming Messages Using Variables
You can use TakeProfit variables to dynamically form the content of the message.
**Common variables:**
* `{{ticker}}` — The instrument's ticker.
* `{{exchange}}` — Exchange name.
* `{{condition_type}}` — Type of trigger condition.
* `{{condition_source_1}}` — Condition source (e.g., price).
**Example usage in the Message field:**
```json
{
"content": "🔔 Alert: {{ticker}} on {{exchange}} — {{condition_type}} {{close}}"
}
```
***
## Configuration Examples
### Example 1: Simple Text Message
**Message:** `The price of BTC/USD exceeded $50,000 on Binance`
**Payload in the Message field:**
```json
{
"content": "🔔 Alert: The price of {{ticker}} exceeded {{close}} on {{exchange}}"
}
```
### Example 2: Sending an Embedded Message (Embed)
**Payload with Embed:**
```json
{
"embeds": [
{
"title": "📈 {{ticker}} Alert",
"description": "**Condition:** {{condition_type}}\n**Price:** {{close}}\n**Exchange:** {{exchange}}",
"color": 3066993
}
]
}
```
* **title**: Message title, can contain variables.
* **description**: Main content using Markdown for formatting.
* **color**: Color of the Embed bar in decimal RGB format (e.g., `3066993` for green).
***
## Testing the Configuration
1. **Save the alert settings** in TakeProfit.
2. **Create a condition** that will surely trigger (e.g., set the price above the current one).
3. **Check for the message** in your Discord channel.
4. **Ensure** that all variables have been correctly replaced with actual data.
***
## Troubleshooting
* **Messages are not received:**
* Check the correctness of the Webhook URL.
* Ensure that the alert in TakeProfit is active.
* **Incorrect message display:**
* Verify the correctness of the JSON in the Payload.
* Use a [JSON validator](https://jsonlint.com/) to check.
* **Variables are not replaced:**
* Ensure the variables are spelled correctly.
* Check if the used variables are supported by the TakeProfit platform.
***
## Helpful Tips
* **Advanced Embed Features:**
* You can add fields, images, and other elements to the Embed. Refer to the [Discord documentation](https://discord.com/developers/docs/resources/channel#embed-object) for details.
* **Notifications in multiple channels:**
* Create multiple Webhooks for different channels and set up corresponding alerts.
* **Security:**
* Do not share the Webhook URL with unauthorized individuals.
* Regularly check your server's security settings.
***
## Conclusion
You have now set up integration between **TakeProfit** and **Discord** via Webhook. This allows you to receive instant and visual notifications about important events, helping you to respond promptly to market changes.
If you have any questions or need additional assistance, refer to the official Discord documentation or contact TakeProfit support.
***
**Useful Links:**
* [Discord Developer Portal — Webhook Documentation](https://discord.com/developers/docs/resources/webhook)
* [Discord Embed Visualizer](https://leovoel.github.io/embed-visualizer/) — a tool for previewing Embeds.
* [TakeProfit — Official Website](https://takeprofit.com/)
* [JSON Validator](https://jsonlint.com/)
***
**Note:** Always stay updated on the APIs and functions you use, as they may be updated or changed over time.
# How to Use a Variable Value in Alert
Source: https://takeprofit.com/docs/guide/alerts/How-use-variable-InAlert
You can use special placeholders to access variable values in alert's message. For example, you can create an alert on NASDAQ:TSLA and type in a message box:
```
{{ticker}}:{{exchange}} {{condition_type}} {{condition_source_1}}
```
The alert will display the message "TSLA Crossing Down 144.68" when triggered.
Here is a list of available placeholders:
```
// Supported placeholders for the message_template field:
//
// {{exchange}} - The exchange where the instrument is traded (e.g., NASDAQ, NYSE).
// {{ticker}} - The ticker symbol of the instrument (e.g., TSLA for Tesla).
// {{time_frame}} - The time frame of the alert (e.g., 1m, 1h).
// {{session}} - Trading session for the main instrument (`regular` or `extended`)
//
// {{condition_type}} - The type of condition that triggered the alert (e.g., crossing, reaching).
//
// {{open}} - The opening price of the main instrument.
// {{high}} - The highest price of the main instrument.
// {{low}} - The lowest price of the main instrument.
// {{close}} - The closing price of the main instrument.
// {{volume}} - The trading volume of the main instrument.
// {{time}} - The time of the price bar for the main instrument.
//
// {{condition_source_0}} - The first series value (e.g., 144.68).
// {{condition_source_1}} - The second series value, if applicable.
// {{condition_source_2}} - The third source value, if applicable.
//
// {{time_now}} - The current time when the alert is triggered.
```
# Telegram Notifications
Source: https://takeprofit.com/docs/guide/alerts/Telegram-webhook
This guide will help you configure automatic notifications from the **TakeProfit** platform to **Telegram** using your own bot and Webhook. This allows you to receive timely alerts directly in the messenger, enhancing your workflow efficiency.
## Creating a Telegram Bot
Begin by creating your own Telegram bot, which will send you messages.
### Obtaining the API Token
1. **Open Telegram** and search for [@BotFather](https://t.me/BotFather).
2. **Create a new bot:**
* Send the command `/newbot`.
* Follow the instructions to set your bot's name and username.
3. **Receive the API token:**
* After creation, BotFather will send you an API token. Example: `123456789:ABCDefGhIJKlmNoPQRsTUVwxyZ`.
* **Save this token** securely; you'll need it for further setup.
***
## Obtaining the Chat ID
To send messages, you need the chat identifier (`chat_id`) where the bot will send notifications.
### For Personal Messages
1. **Start a conversation with your bot:**
* Open a chat with your bot and send `/start`.
2. **Get your `User ID`:**
* Search for [@userinfobot](https://t.me/userinfobot).
* Send any message to it.
* It will reply with your `User ID` and other information.
### For Group Chats
1. **Create or use an existing group.**
2. **Add your bot to the group.**
3. **Obtain the group's `Chat ID`:**
* Add [@userinfobot](https://t.me/userinfobot) to the same group.
* Send a message in the group.
* [@userinfobot](https://t.me/userinfobot) will provide the group's `Chat ID`.
**Important:** Ensure your bot has the necessary permissions in the group to send messages.
***
## Configuring Webhook in TakeProfit
Setting up a Webhook allows the TakeProfit platform to send notifications to your bot.
### Preparing the Webhook URL
Create the URL for the Telegram API:
```
https://api.telegram.org/bot/sendMessage
```
* **Replace** `` with the token from step 1.
**Example:**
```
https://api.telegram.org/bot123456789:ABCDefGhIJKlmNoPQRsTUVwxyZ/sendMessage
```
### Setting Up Webhook in the Platform
1. **Log in** to your **TakeProfit** account.
2. **Create a new alert** or edit an existing one.
3. **Set up alert conditions:**
* Specify parameters like ticker, exchange, trigger condition, etc.
4. **Add the Webhook:**
* In the notifications section, select **Webhook URL**.
* **Paste the Webhook URL** you prepared.
5. **Configure the Payload:**
* In the **Message** field, enter JSON with `chat_id` and `text` parameters.
**Example Payload:**
```json
{
"chat_id": "YOUR_CHAT_ID",
"text": "YOUR_MESSAGE"
}
```
* **Replace** `YOUR_CHAT_ID` with your `User ID` or group `Chat ID`.
* **Replace** `YOUR_MESSAGE` with your notification text or use TakeProfit variables.
***
## Forming a Message Using Variables
### Using TakeProfit Variables
TakeProfit allows the use of variables for dynamic message content.
**Common variables:**
* `{{ticker}}` — The instrument's ticker.
* `{{exchange}}` — Exchange name.
* `{{condition_type}}` — Type of trigger condition.
* `{{condition_source_1}}` — Condition source (e.g., price).
**Example in the Message field:**
```json
{
"chat_id": "987654321",
"text": "Alert for {{ticker}} on {{exchange}}: {{condition_type}} at {{condition_source_1}}"
}
```
When the alert triggers, the variables will be replaced with real-time values.
***
## Configuration Examples
### Example 1: Simple Text Message
**Details:**
* **Bot Token:** `123456789:ABCDefGhIJKlmNoPQRsTUVwxyZ`
* **Chat ID:** `987654321`
* **Message:** `BTC price exceeded $50,000`
**Webhook URL:**
```
https://api.telegram.org/bot123456789:ABCDefGhIJKlmNoPQRsTUVwxyZ/sendMessage
```
**Payload in the Message field:**
```json
{
"chat_id": "987654321",
"text": "{{ticker}} price exceeded ${{close}}"
}
```
### Example 2: Sending JSON Data
**Objective:** Send structured JSON with alert data.
**Payload:**
```json
{
"chat_id": "987654321",
"text": "{ \"symbol\": \"{{ticker}}\", \"exchange\": \"{{exchange}}\", \"price\": \"{{close}}\" }"
}
```
**Important:** Escape quotes inside `text` with a backslash (`\`).
**Example of the final message:**
```json
{
"symbol": "BTC/USD",
"exchange": "Binance",
"price": "50000"
}
```
***
## Testing the Configuration
1. **Create a test alert** with the settings you've configured.
2. **Check for the message** in your Telegram app.
* If the message doesn't arrive, double-check your settings and JSON formatting.
3. **Verify the data**, ensuring variables are correctly replaced.
***
## Troubleshooting
* **Messages are not delivered:**
* Ensure the `chat_id` and bot token are correct.
* Confirm the bot isn't blocked and has access to the chat or group.
* **Formatting errors:**
* Use a JSON validator to check the Payload's correctness.
* Make sure all special characters are properly escaped.
* **Variables are not replaced:**
* Verify the variables are spelled correctly.
* Ensure the variables are supported by TakeProfit.
***
## Helpful Tips
* **Using Telegram Formatting:**
* Add `"parse_mode": "Markdown"` or `"parse_mode": "HTML"` to the Payload for text formatting.
* **Example:**
```json
{
"chat_id": "987654321",
"text": "*BTC price exceeded $50,000!*",
"parse_mode": "Markdown"
}
```
* **Sending Messages to Multiple Chats:**
* Create multiple alerts with different `chat_id`s.
* Alternatively, implement distribution within the bot (requires additional programming).
* **Security:**
* Never share your bot's token with anyone.
* Ensure the Webhook URL doesn't contain sensitive information.
***
## Conclusion
You have now set up integration between **TakeProfit** and **Telegram** using your own bot. This enables you to receive instant notifications about important events and respond promptly to market changes.
If you encounter questions or difficulties, refer to the official Telegram Bot API documentation or contact TakeProfit support.
***
**Useful Links:**
* [Telegram Bot API Documentation](https://core.telegram.org/bots/api#sendmessage)
* [TakeProfit — Official Website](https://takeprofit.com/)
* [JSON Validator](https://jsonlint.com/)
***
**Note:** Always verify the APIs and functions you use are up to date, as they may change over time.
# Notifications via Webhooks
Source: https://takeprofit.com/docs/guide/alerts/Webhook-notifications
Webhooks allow you to automate the transfer of data and notifications from the **TakeProfit** platform to other applications and services in real-time. This guide will help you set up notifications via webhooks in TakeProfit for integration with various services such as Telegram, Discord, Slack, or your own servers.
## What is a Webhook in the Context of TakeProfit
A **Webhook** is a mechanism by which **TakeProfit** automatically sends HTTP requests to a specified URL when certain events occur, such as an alert triggering. This allows you to integrate TakeProfit with other services, receiving notifications and data in real-time.

## How Webhooks Work in TakeProfit
1. **Alert Triggering**: When a specified alert condition in TakeProfit is met (e.g., the price of an asset reaches a certain level), the platform initiates a webhook.
2. **Sending an HTTP Request**: TakeProfit automatically sends an HTTP request (`POST` method) to the URL you have configured for the webhook, transmitting data about the triggered alert in JSON format.
3. **Receiving and Processing Data**: The service or application to which the webhook is directed receives the request and processes the data according to its settings (e.g., sends a notification to a user, updates a database, executes a trading operation).
***
## Steps to Set Up Notifications via Webhooks in TakeProfit
### 1. Preparing the Webhook Receiver
The **Webhook Receiver** is the service or application that will receive and process data from TakeProfit.
* **Choosing a Receiver Service**:
* **Messengers**: Telegram, Discord, Slack, etc.
* **Third-Party Services**: IFTTT, Zapier, etc.
* **Own Server**: Your own server or API for data processing.
* **Creating or Configuring a URL to Receive the Webhook**:
* **For Messengers**:
* **Telegram**: Create a bot via [@BotFather](https://t.me/BotFather) and obtain an API token.
* **Discord**: Create a webhook in the server channel settings.
* **Slack**: Set up an Incoming Webhook in the Slack app.
* **For Your Own Server**:
* Configure an endpoint on your server to receive HTTP requests.
* Ensure processing of incoming data and implementation of the necessary logic (e.g., writing to a database, sending messages).
* **For Third-Party Services**:
* Follow the instructions of the chosen service to obtain the webhook URL and set up the integration.
### 2. Obtaining the Webhook URL
* **Copy or save the webhook URL** that will be used in TakeProfit.
* **Ensure the Security of the URL**: Do not share it publicly to avoid unauthorized access or spam.
### 3. Configuring the Webhook in TakeProfit
1. **Log in to your account** on the **TakeProfit** platform.
2. **Create a new alert** or edit an existing one:
* Specify the necessary alert parameters: **ticker**, **exchange**, **trigger condition**, **timeframe**, etc.
3. **Add the Webhook in the Notification Settings**:
* In the **Notifications** section, select the **Webhook URL** option.
* **Paste the webhook URL** obtained in the previous step.
4. **Configure the Payload** (request body):
* In the **Message** field, enter the JSON with the data that will be sent when the alert triggers.
* Use TakeProfit variables to dynamically form the message.
**Example Payload:**
```json
{
"ticker": "{{ticker}}",
"exchange": "{{exchange}}",
"price": "{{close}}",
"condition": "{{condition_type}}",
"time": "{{time_now}}"
}
```
### 4. Using TakeProfit Variables
TakeProfit provides a number of variables that can be used in the Payload:
* `{{ticker}}` — The instrument's ticker (e.g., BTC/USD).
* `{{exchange}}` — The exchange name (e.g., Binance).
* `{{condition_type}}` — The type of trigger condition (e.g., Crossing Up).
* `{{condition_source_1}}` — The source of the first condition (e.g., closing price).
* `{{close}}` — The closing price of the last bar.
**Note:** A full list of available variables can be found in [this article](/guide/alerts/How-use-variable-InAlert) or in the interface when creating an alert.
### 5. Saving and Activating the Alert
* **Check the correctness of the alert settings** and webhook, including the correctness of the URL and the JSON syntax in the Payload.
* Click **Create Alert** or **Save** to save and activate the alert.
***
## Testing the Webhook
1. **Trigger the Alert**: Set a condition that is easy to fulfill so that the alert triggers (e.g., price below the current level).
2. **Check for Notification Receipt** on the webhook receiver side (e.g., in Telegram, Discord, or your server).
3. **Debugging**:
* If the notification is not received, check the correctness of the webhook URL.
* Ensure that the Payload format meets the receiver's requirements and is correctly formed (check the JSON syntax).
* Check logs on the receiver side to identify possible errors or reasons for failure.
***
## Examples of Using Webhooks in TakeProfit
### 1. Sending Notifications to Telegram
* **Create a bot** in Telegram via [@BotFather](https://t.me/BotFather) and obtain the API token.
* **Obtain your Chat ID** (for a personal chat or group) using the bot [@userinfobot](https://t.me/userinfobot).
* **Form the URL for sending messages** via the Telegram API:
```
https://api.telegram.org/bot/sendMessage
```
* **Configure the Payload** in TakeProfit:
```json
{
"chat_id": "YOUR_CHAT_ID",
"text": "🔔 Alert: {{ticker}} on {{exchange}} reached {{condition_source_1}}.\nPrice: {{close}}"
}
```
### 2. Integration with Discord
* **Create a Webhook** in Discord:
* Go to the channel settings on your server.
* In the **Integrations** section, select **Webhooks** and create a new one.
* **Copy the webhook URL**.
* **Configure the Payload** in TakeProfit:
```json
{
"content": "🔔 **Alert for {{ticker}}**\nExchange: {{exchange}}\nPrice: {{close}}\nCondition: {{condition_type}}"
}
```
### 3. Sending Data to Your Own Server
* **Set up your server** to receive `POST` requests at a specific URL.
* **Process the data** received from TakeProfit according to your requirements (e.g., saving to a database, initiating automated trading).
* **Use the Payload** to transmit the necessary data:
```json
{
"symbol": "{{ticker}}",
"exchange": "{{exchange}}",
"price": "{{close}}",
"condition": "{{condition_type}}",
"time": "{{time_now}}"
}
```
***
## Best Practices and Tips
* **Security**:
* **Keep the webhook URL secret** to prevent unauthorized access.
* **Use authentication**: If possible, add parameters to authenticate requests.
* **Data Format**:
* **JSON Validation**: Use JSON validators to ensure the syntax is correct.
* **Escaping Characters**: Escape special characters in strings if necessary.
* **Debugging and Monitoring**:
* **Logging**: Enable logging on the webhook receiver side to track received requests and possible errors.
* **Testing**: Regularly test the webhooks, especially after making changes to settings or platform updates.
* **Using Variables**:
* **Up-to-date Data**: Use variables to get current data each time the alert triggers.
* **Availability Check**: Ensure that the variables used are supported by TakeProfit and work correctly.
* **Documentation**:
* **Study the official TakeProfit documentation** for detailed information on webhook capabilities and available variables.
***
## Conclusion
Setting up notifications via webhooks in the **TakeProfit** platform provides powerful opportunities for integration with other services and automating your workflows. By following this guide and adhering to best practices, you can effectively configure webhooks and receive notifications in a format convenient for you, allowing you to respond promptly to market changes.
***
**Note**: Always keep up-to-date with the TakeProfit platform documentation and the services you integrate with, as functionality may be updated and changed over time.
# Profile Settings
Source: https://takeprofit.com/docs/guide/getting-started/Profile-settings
## Public Profile Settings

The Profile Settings section allows you to manage your public profile information, including:
* Display name
* Username
* Bio (up to 150 symbols)
* Date of birth
* Location
* Website.
## Billing Settings

From the Billing tab, you can:
* Cancel subscription (if on a paid plan)
* Upgrade to Pro plan (if on Freeroll)
* Modify payment methods
* View billing history.
## Payment Methods

To manage your payment methods:
1. Click the "Edit" link.
2. In the "Update your payment method" dialog:

* Click "Add a new card" to add new payment methods
* Set a default payment method
* View the default payment notice: "This payment method will be used to pay for all purchases on [TakeProfit.com](http://TakeProfit.com)".
### Important Payment Information
* Multiple cards can be added
* Only one card can be set as default payment method
* Default payment method cannot be deleted unless a new one is added
* All payments are processed through the Stripe platform. TakeProfit does not store or process your payment information
* To remove all payment data, contact [support@takeprofit.com](mailto:support@takeprofit.com).
### Payment Method Deletion

* Click the trash icon next to a payment method to remove it. **Note**: The default payment method cannot be deleted unless a new default is set.
* For complete payment data removal, email us [support@takeprofit.com](mailto:support@takeprofit.com).
# Registration
Source: https://takeprofit.com/docs/guide/getting-started/Registration
Getting started with TakeProfit is a straightforward process that takes just a couple of minutes. This guide will walk you through the registration process step by step.
### Creating a New Account
There are two ways to initiate the registration process:
1. Click the "Get Started" button in the top right corner of the website

2. Start interacting with the platform at takeprofit.com/platform, where you'll be automatically prompted to register.

### Account Creation Options
You can create your account using one of these methods:
1. Social media accounts:
* Google account
* Apple ID
* Facebook
* X (formerly Twitter).
2. Email registration.
**Note:** When using social media authentication, no password is required. You'll always be able to log in using the same authentication method you chose during registration.
**Important:** If you want to login using the email address associated with your social media account, you'll need to verify your email ownership:
* We'll send you a verification email
* Click the link in the email
* This will establish a connection between your email login and social media account
* After verification, you can use either method to access your account.
### Account Verification Process
1. After selecting your registration method, you'll need to verify your account by confirming your email address:
* For social media registrations: The platform will use the email associated with your social media account
* If your social media account doesn't have an associated email, you'll be prompted to provide one (this is mandatory).
2. Email Verification:
* You'll receive a verification email
* Either click the "Verify Email" button in the email
* Or copy and paste the verification link into your browser
3. After verification, you'll be automatically redirected to [takeprofit.com](http://takeprofit.com).
### Setting Up Your Username
The final step is creating your username:

* By default, the system uses the first part of your email address.
* You can customize your username to any available name that meets the platform's requirements.
* The platform will provide real-time feedback on:
* Whether your chosen username is available
* If it meets the platform's naming requirements
* Any naming restrictions.
**Important:** Once you complete these steps, you'll have full access to:
* Comment on posts
* Create your own posts
* Use the platform's features after activating your trial period.
# Trial and Subscription Plans
Source: https://takeprofit.com/docs/guide/getting-started/Trial-activation-subscriptions
After completing your registration, you'll automatically see a popup offering a trial period of the platform.

Here's what you need to know:
### Trial Period
* Duration: 7 days for monthly and 30 days for annual All-in plan, respectively
* Full access to all platform features
* No credit card required to start.
### Subscription Options
After the trial period ends, you have two options:
1. **All-in Plan**
* Full platform functionality
* Recommended for active traders
* Details available at [takeprofit.com/prices](https://takeprofit.com/prices).
2. **Freeroll Plan**
* Automatically activated if Pro subscription is not purchased
* Limited functionality
* Basic features remain available
* Full plan comparison available at [takeprofit.com/prices](https://takeprofit.com/prices).
# User Profile Page
Source: https://takeprofit.com/docs/guide/getting-started/User-Profile
Your public profile is accessible at [https://takeprofit.com/@username](https://takeprofit.com/@username), where `@username` is your unique identifier chosen during registration. This page serves as your personal hub on TakeProfit platform.

## Profile Content
Your profile page displays:
* All your published posts
* Published indicators from the marketplace
* Personal screeners
* Draft posts and indicators (in the "Drafts" tab).
## Profile Statistics
The profile page shows:
* Account registration date
* Number of followers
* Number of accounts you follow
* Clickable follower/following counts to view detailed lists.
## Additional Features

* Personal referral link (see Referral Program section for details)
* Quick access to Profile Settings
* Direct link to profile editing.
# Workspace Templates
Source: https://takeprofit.com/docs/guide/getting-started/Workspace-Template-Selection
After activating your trial, the next step is selecting your workspace template. This crucial step will define your trading environment.

## Available Templates
TakeProfit offers two main approaches to setting up your workspace:
### Pre-built Templates

1. Designed for different trading styles
2. Ready-to-use configurations
3. Optimized layouts for various trading approaches.
### Blank Workspace

1. Start from scratch
2. Full customization freedom
3. Add widgets according to your needs.
Use filters like Chart, Screener etc. to discover templates that match your trading style.
# null
Source: https://takeprofit.com/docs/indie/Algorithms-for-series-processing
Due to the real-time nature of a candle chart, most of tech analysis indicators work according to principles of a
*sliding window* technique. Indie has `@algorithm` decorator and `SeriesF`, `MutSeriesF` data types which help to create
algorithms that use this technique. All this provides an effective and convenient way for *series processing*.
## `@algorithm`, `SeriesF` and `MutSeriesF`
Decorator [`@algorithm`](/indie/Library-reference/package-indie#decor_algorithm) is a syntactic sugar that can be applied to a function
definition which is equivalent to writing a class definition of an algorithm inherited from `indie.Algorithm` class.
More details about how this kind of syntactic sugar works are [here](/indie/How-Indies-syntactic-sugar-works).
[`SeriesF`](/indie/Library-reference/package-indie#class_SeriesF) is a data type that represents series of numeric values like prices of
some instrument. Every element of a `SeriesF` object stores a value at time of some bar on a chart. `SeriesF` objects
have an interface which gives access to their values with square brackets operator. For example, series of close prices
of some instrument is `self.close` (where `self` is an object with `Context` interface) and current (the last) close
price can be accessed with expression `self.close[0]`. The close price at the previous candle is `self.close[1]` and so
on.
Series objects like `self.open`, `self.high`, `self.low`, `self.close` and `self.volume` are built-in and read-only. But
Indie lets you create your own series objects, put some values that your algorithm calculates into them and use them in
the further parts of your indicator code. This is exactly what `MutSeriesF` type is intended to be used for.
Function [`MutSeriesF.new`](/indie/Library-reference/package-indie#func_MutSeriesF_new) wraps any primitive number value and returns
an object of `MutSeriesF` type with that value written into the `[0]` (the most recent element). This provides access to
previous values of that value in the future Indie invocations. In other words, `MutSeriesF` data type is what you need
if you want to persist some value over bars.
NOTE: `MutSeriesF` is a type alias for `MutSeries[float]` and `SeriesF` is a type alias for `Series[float]`. In future
versions of Indie it is planned to support other types for element of those containers besides `float`.
## SMA, Sum and sliding window technique
Now it is a good time to look at some of the algorithms in action. Let us take some very basic indicator like for
example *Simple moving average* (SMA) and see how it works under the hood. To calculate SMA with length=4 of some price
series, we have to divide every element of a corresponding *sum* (with the same length=4) by it's length. That is why,
first we have to look in detail how sum algorithm could be implemented.
The sum of length=4 could be calculated very simple. First, the value of `sum_0` (where `0` is the bar index) is
undefined, because at that point there is only one price is available in the input series. Same with the `sum_1` and
`sum_2`. But the value of `sum_3` equals to `price_0 + price_1 + price_2 + price_3` which is `5 + 2 + 1 + 2 = 10`.
So far so good and the next sum value, `sum_4`, equals to `price_1 + price_2 + price_3 + price_4` which is
`2 + 1 + 2 + 4 = 9` correspondingly. Finally, in the same manner we calculate `sum_5` as
`price_2 + price_3 + price_4 + price_5` which is `1 + 2 + 4 + 6 = 13`. And so on, this is illustrated on the diagram:
Calculation of a sum in a straightforward (but non-effective by time) way:
```txt
ctx.bar_index: 0, 1, 2, 3, 4, 5, ...
price: 5, 2, 1, 2, 4, 6, ...
_, ...
_, _, ...
_, _, _, ...
_, _, _, 10, ...
_, _, _, 10, 9, ...
sum(length=4): _, _, _, 10, 9, 13, ...
```
Here is Indie implementation of this algorithm:
```py
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def Sum(self, price: SeriesF, length: int) -> SeriesF:
result = 0.0
for i in range(length):
result += price[i]
return MutSeriesF.new(result)
```
Reader may notice that we have to sum the same price values more than once. We may calculate the next sum values more
efficiently using the sum value calculated on a previous step. For example `sum_4 = sum_3 - price_0 + price_4`,
`sum_5 = sum_4 - price_1 + price_5` and so on. This other way of calculation is exactly the mentioned before
*sliding window* technique. It turns out that with larger lengths the second way is way more efficient in terms of time.
And here is the Indie implementation of it:
```py
# indie:lang_version = 5
from math import nan
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def Sum(self, price: SeriesF, length: int) -> SeriesF:
s = MutSeriesF.new(init=0)
s[0] += price[0]
result: float
if len(price) > length:
s[0] -= price[length]
result = s[0]
else:
result = nan
return MutSeriesF.new(result)
```
NOTE: If you need a [Sum](/indie/Library-reference/package-indie-algorithms#class_alg_Sum) or [SMA](/indie/Library-reference/package-indie-algorithms#class_alg_Sma) you don't
have to implement them by yourself. Simply import them from the standard library like this:
`from indie.algorithms import Sum, Sma`.
Now, after we have a `Sum` algorithm, it is trivial to write SMA as `Sma` algorithm too:
```py
@algorithm
def Sma(self, price: SeriesF, length: int) -> SeriesF:
s = Sum.new(price, length)
return MutSeriesF.new(s[0] / length)
```
As you can see, it is very easy to call one algorithm from another. It is very natural to connect them in a sort of a
chain. That is why all the functions decorated with `@algorithm` return `SeriesF` result (or tuple of `SeriesF` values).
Finally here is the `Main` entry point of our indicator that plots it on chart:
```py
@indicator('SMA Example', overlay_main_pane=True)
def Main(self):
result = Sma.new(self.close, 12)
return result[0]
```
## Series behavior during history vs runtime
Suppose we have an indicator that counts green bars of an instrument on a chart:
```py
# indie:lang_version = 5
from indie import indicator, MutSeriesF
@indicator('Green bars counter')
def Main(self):
green_count = MutSeriesF.new(init=0)
if self.close[0] > self.open[0]:
green_count[0] += 1
return green_count[0]
```

Bar coloring traditionally works this way: if closing price of a bar is greater than it's opening price, then the bar is
green, otherwise it is red. In the Indie code we have a series `green_count` object which accumulates the desired count.
This count is returned from `Main` which plots a blue line on a chart. On Figure 6.1 we see how blue line raises up by 1
on every green bar and stays flat if bar is red. First let us take a close look at how this Series object behaves during
indicator calculation on a historical bars of some imaginary instrument. Close and open prices of our instrument could
be for example:
```txt
time: t0, t1, t2, t3, t4, t5
open: 9, 18, 8, 7, 8, 15
close: 12, 7, 14, 13, 12, 5
```
History prices `open` and `close` will be passed to the indicator for calculation one by one from left to right.
Indicator will calculate, at time `t0`, like this '12 is greater than 9, so we add 1 to green\_count'. On the next
calculation, at time `t1`, it will be '7 is not greater than 18, so do nothing. Value of green\_count is still 1'. In the
end, `green_count` series will contain these values:
```txt
time: t0, t1, t2, t3, t4, t5
green_count: 1, 1, 2, 3, 4, 4
```
Thus, during the calculation of indicator on historical data everything is simple, predictable and very natural.
Let us suppose that starting from time `t6` the realtime begins:
```txt
time: t6, t6, t6, t7, t7, t7, t7, t8, t8, t9, ...
open: 6, 6, 6, 11, 11, 11, 11, 7, 7, ...
close: 10, 2, 12, 14, 12, 16, 9, 5, 12, ...
```
Our indicator will behave like this:
```txt
time: t6, t6, t6, t7, t7, t7, t7, t8, t8, t9, ...
green_count: 5, 4, 5, 6, 6, 6, 5, 5, 6, ...
last bar update: ^ ^ ^
```
Moments of the final bar update are marked with `^`s. They are important, because values calculated in these moments are
stored in the end in the `green_count` series, overwriting all values written there before at the time of the same bar.
Bar usually updates multiple times at realtime. Every realtime update of a bar triggers a calculation of indicator.
Right before every such calculation the state of the `green_count[0]` series element resets to it's previous value (i.e.
`green_count[1]`) — the value it had at the time of previous bar. That is why during the three updates of bar starting
at `t6`, corresponding element of `green_count` series was set to 5 at first, then reverted back to 4, then finalized at
value 5.
If nothing is written in the `green_count[0]` series element and bar finalizes then this value is carried further to
the next series element without change.
## `MutSeriesF.new()` function description
```py
MutSeriesF.new(
reset: indie.Optional[float] = None,
init: indie.Optional[float] = None,
size: indie.Optional[int] = None,
) -> indie.MutSeriesF
```
Function `MutSeriesF.new` creates `MutSeriesF` objects which are containers for calculated values in Indie code. The
main feature of `MutSeriesF` container is ability to store (or 'remember') historical values of some variable, those
values could be later accessed with the square brackets operator. At the moment `MutSeriesF` class supports only
`float` type as series element.
Please note that `MutSeriesF` objects give read-write access only to the last value of the series object and read access
to any (well, down to some limit) previous values.
Parameters:
* `reset` — is a value that is written into the most recent element of the `MutSeriesF` every time `MutSeriesF.new()`
function is executed. The effect of this parameter is the same as:
```py
# this:
s = MutSeriesF.new(reset_val)
# is the same as:
s = MutSeriesF.new()
s[0] = reset_val
```
* `init` — is a value that is written into the most recent element of the series object only once after the `MutSeriesF`
object was created. Or, in other words, it is a value that is written only at the time of the first `MutSeriesF.new()`
function call.
```py
# this:
s = MutSeriesF.new(init=init_val)
# is similar to:
s = MutSeriesF.new()
if self.bar_index == 0:
s[0] = init_val
```
* `size` — is number of elements that `MutSeriesF` object should persist in memory. The default and minimum possible
size is 2, which means that a series of size=2 stores in memory one value at the time of the last candle and another
at the time of the previous candle. The size is automatically expanded during the historical calculation of an
indicator. For example:
```py
# This series allows us to get access to s[0], s[1] and s[2] elements from now
s = MutSeriesF.new(0.0, size=3)
# We can read previous value which is out of size=3, for example s[5]:
s[0] = s[5] + 1
```
The size of `s` was expanded from 3 to 6. It is allowed to get access to s\[0], s\[1], s\[2], s\[3] and s\[4], s\[5] elements
after that. It may seem to have not very much sense at first. We set some size, but we are allowed to expand it later.
Well, it is allowed to expand the size only during the calculation of indicator history. The algorithm by some reason
may calculate the lookback offset for some series at runtime, depending on prices for example like this:
```py
max_size = 100
offset = min(math.round(self.close[0]), max_size)
s = MutSeriesF.new(init=0.0, size=max_size)
a = s[offset] # calc something with it...
```
We cannot predict values of `self.close` series. They could be less than `max_size = 100` at first but then during
realtime, they could rise higher. That is why we should always limit the max\_offset with `min` and reserve the `s`'s
size with `size` parameter. Otherwise the indicator would fail, since, again, we cannot expand the size at realtime.
NOTE: `MutSeriesF` objects also have a method `request_size(new_size: int)` which can be used to expand the size
explicitly.
`MutSeriesF.new` function has a 'get or create' semantics. It means that only one `MutSeriesF` object is created per one
`MutSeriesF.new` function call occurrence in the code. All subsequent calls of `MutSeriesF.new` in exactly the same
position in Indie script simply return `MutSeriesF` objects created previously. For example:
```py
@indicator('Example')
def Main(self):
s1 = MutSeriesF.new(0.0)
s2 = MutSeriesF.new(42.0)
# ...
```
In this code only two `MutSeriesF` objects are created: `s1` and `s2`. The `Main` function is called multiple times -
per every historical candle and per every realtime update of the last candle — thus multiple times `MutSeries.new`
functions are called too. But only when `self.bar_index == 0` the `s1` and `s2` objects are created. During all the
subsequent calls, `s1` and `s2` only receive references to existing `MutSeriesF` objects. If you want more details about how `MutSeriesF.new` function works, read [this](https://takeprofit.com/docs/indie/How-Indies-syntactic-sugar-works#mutseriesfnew-method).
## TL;DR: How to use classes from `indie.algorithms` package in my indicator?
Suppose we have found an algorithm (e.g. [RSI](/indie/Library-reference/package-indie-algorithms#class_alg_Rsi)) in the Indie library and want to use
it in our indicator. These are the steps which should be done in order to achieve this:
* Import the class of the desired algorithm, which in our example let it be the `indie.algorithms.Rsi`:
```py
from indie.algorithms import Rsi
```
* Go to the place in the code where you want to call the algorithm. Algorithms can be called either:
* from [`Main`](/indie/How-Indies-syntactic-sugar-works#main-entry-point) entry point or
* from [secondary context](/indie/How-Indies-syntactic-sugar-works#functions-decorated-with-sec_context) entry point or
* from some other [algorithm](/indie/How-Indies-syntactic-sugar-works#functions-decorated-with-algorithm).
In our example we go to the `Main` entry point function:
```py
@indicator('Test')
def Main(self):
# ...
# >>> somewhere here <<<
# ...
```
NOTE: that you cannot call algorithm's `new()` function from global scope of indicator or from some 'plain old python
function'.
* Call the algorithm's `new()` *syntactic sugar* function according to it's signature which for `Rsi` is
`new(src: indie.SeriesF, length: int) -> indie.SeriesF` (here is the
[link](/indie/Library-reference/package-indie-algorithms#func_alg_Rsi_new)) and write the resulting series of RSI values to some variable,
e.g. `rsi_result`:
```py
@indicator('Test')
def Main(self):
rsi_result = Rsi.new(self.close, 12)
# ...
```
* From now you may use the `rsi_result` series, for example, return it from `Main` for plotting on chart or pass to some other algorithm for further processing. If you want just access the last `float` RSI value, use square brackets operator `rsi_result[0]`.
Final version of our example looks like this:
```py
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Rsi
@indicator('Example')
def Main(self):
rsi_result = Rsi.new(self.close, 12)
return rsi_result[0]
```
## TL;DR: How to use `indie.MutSeriesF` in my indicator?
Suppose we are working on an indicator where we calculate some math formula on every candle. Let us take something simple like `OC2 = (OpenPrice + ClosePrice) / 2` as an example of such a formula. Here is Indie code that calculates and plots `OC2`:
```py
# indie:lang_version = 5
from indie import indicator
@indicator('Example', overlay_main_pane=True)
def Main(self):
OC2 = (self.open[0] + self.close[0]) / 2
return OC2
```
NOTE: That type of `OC2` variable is `float`.
It could be very useful to store such a value like `OC2` (or, to be more accurate, a *series of values* because we
calculate new value on each candle) in a Series-like container (which is `indie.MutSeriesF`). This gives following
benefits:
* it will be possible to access historical values of `OC2` (values which were calculated previously on historical
candles);
* it will be possible to process series of `OC2` values with algorithms from `indie.algorithms` package (or our own).
Here is how to do it:
* Import class `indie.MutSeriesF` to your indicator:
```py
from indie import MutSeriesF
```
* Wrap the value with `indie.MutSeriesF.new()` *syntactic sugar* static method:
```py
OC2 = MutSeriesF.new((self.open[0] + self.close[0]) / 2)
```
Since this moment, type of `OC2` variable is `indie.MutSeriesF`, which is a container with `float` values inside.
Please note, that `indie.MutSeriesF.new()` method can be called either:
* from [`Main`](/indie/How-Indies-syntactic-sugar-works#main-entry-point) entry point or
* from [secondary context](/indie/How-Indies-syntactic-sugar-works#functions-decorated-with-sec_context) entry point or
* from some [algorithm](/indie/How-Indies-syntactic-sugar-works#functions-decorated-with-algorithm).
NOTE: that you cannot call `indie.MutSeriesF.new()` function from global scope of indicator or from some 'plain old
python function'.
* Use the `OC2` series in further calculations:
* access historical values of `OC2` variable with the square brackets operator. For example:
```py
# indie:lang_version = 5
from indie import indicator, MutSeriesF
@indicator('Example', overlay_main_pane=True)
def Main(self):
OC2 = MutSeriesF.new((self.open[0] + self.close[0]) / 2)
return OC2[0], OC2[1], OC2[2]
```
Here `OC2[0]` returns `float` value of our variable on the last candle, `OC2[1]` - value on the previous candle,
`OC2[2]` - value that was 2 candles back and so on.
* process series of `OC2` values with some algorithm, for example SMA, like this:
```py
# indie:lang_version = 5
from indie import indicator, MutSeriesF
from indie.algorithms import Sma
@indicator('Example', overlay_main_pane=True)
def Main(self):
OC2 = MutSeriesF.new((self.open[0] + self.close[0]) / 2)
smoothed_OC2 = Sma.new(OC2, 12)
return smoothed_OC2[0]
```
# null
Source: https://takeprofit.com/docs/indie/Changelog
All notable changes to the Indie language project.
#### Added
* New series-based plotting capabilities:
* `@indie.plot.background`: recolors the background of the chart pane.
* `@indie.plot.bar_color`: recolors the bars/candles on the chart.
* Non-series drawing objects `Label` and `Line` support.
#### Added
* `@indie.plot.marker`: plots circles, crosses and labels (with optional text) above/below candles on the chart.
* Built-in indicators MA Cross and Parabolic Stop And Reverse.
#### Added
* Built-in indicator Least Squares Moving Average.
* Algorithms:
* `indie.algorithms.Macd`
* `indie.algorithms.Mfi`
* `indie.algorithms.Sar`
* `indie.algorithms.SinceTrue`
* `indie.algorithms.Uo`
* Package `indie.math` with functions:
* `cross`
* `cross_over`
* `cross_under`
* `divide`
* Methods of class `datetime.datetime`:
* `strptime`
* `timestamp`
#### Changed
* Updated return type of algorithms:
* `indie.algorithms.SinceHighest`
* `indie.algorithms.SinceLowest`
#### Added
* Underlining of some errors in the Indie IDE.
#### Added
* Indie language v5 support:
* `indie.plot` is now a package, not a decorator.
* Decorators renamed:
```py
@indie.fill() -> @indie.plot.fill()
@indie.plot() -> @indie.plot.line()
@indie.plot(style=plot_style.STEPS) -> @indie.plot.steps()
@indie.plot(style=plot_style.HISTOGRAM) -> @indie.plot.histogram()
@indie.plot(style=plot_style.COLUMNS) -> @indie.plot.columns()
```
* Support of Indie v4 -> v5 migrations in Code Migrator.
* `display_options` parameter for `@plot.*` decorators.
#### Removed
* Indie language v4 support.
* Deprecated decorator `@param.string`, use `@param.str` instead.
* Deprecated field `SymbolInfo.marketdata_timezone`, use `SymbolInfo.timezone` instead.
* Deprecated function `tf`, use `TimeFrame.from_str` instead.
* Deprecated enum `WeekDay`, use `week_day` instead.
#### Added
* Built-in indicator Correlation Coefficient.
* Algorithms `indie.algorithms.Corr` and `indie.algorithms.LinReg`.
#### Added
* Introducing `indie.TradingSession` and `indie.schedule.Schedule` classes for trading sessions support.
#### Added
* Support of `indie.Var[T]` container which is like a `indie.MutSeries[T]` but with history depth of 1.
#### Added
* Expanded OOP support: it is now possible to create custom classes with fields and methods, or to add methods to the
descendants of `indie.Algorithm`, `indie.MainContext`, or `indie.SecContext`.
#### Added
* Generic data types `indie.Series[T]` and `indie.MutSeries[T]`. At the moment `T` can be any of `float`, `int`, `bool`, `str` types.
#### Added
* Indie language v4 support:
* Classes syntax of algorithms and contexts declaration.
* `Context.calc_on` call is required to be called only from context's `__init__` body.
* Support of Indie v3 -> v4 migrations in Code Migrator.
#### Removed
* Indie language v3 support.
#### Added
* Indie language v3 support:
* Package renamed `indie.algorithm` -> `indie.algorithms`.
* Renamed all algorithms in `indie.algorithm` package to CamelCase, e.g. `std_dev` -> `StdDev`
* `Algorithm.new()` syntactic sugar method was introduced.
* Added `self` to every `@func`-decorated function as the first parameter.
* Renamed decorator `@func` -> `@algorithm`. Introduced base class `indie.Algorithm`.
* Renamed `def main(ctx)` -> `def Main(self)`. Introduced base class `indie.MainContext`.
* Syntactic sugar function `mut_series` is replaced with `MutSeriesF.new()`.
* Classes renamed: `MutSeries` -> `MutSeriesF`, `Series` -> `SeriesF`.
* Renamed decorator `@ctx_func` -> `@sec_context`. Introduced base class `indie.SecContext`.
* Renamed the first parameter of a secondary context `ctx` -> `self`.
* Renamed parameter `ctx_func` -> `sec_context` of the function `Context.calc_on`.
* Changed signatures of algorithms:
* `indie.algorithm.since_lowest`, `indie.algorithm.since_highest`
* `indie.algorithm.lowest`, `indie.algorithm.highest`
* `indie.algorithm.adx`
* `indie.algorithm.atr`
* `indie.algorithm.donchian`
* `indie.algorithm.ma`
* `indie.algorithm.mfv`
* `indie.algorithm.net_volume`
* `indie.algorithm.supertrend`
* `indie.algorithm.tr`
* `indie.algorithm.vwap`
* `indie.algorithm.vwma`
* plus all algorithms now return `SeriesF` types instead of `MutSeriesF`.
* Indie Code Migrator microservice for automatic migration of Indie source code from v2 to v3.
#### Removed
* Indie language v2 support.
#### Changed
* Replaced milliseconds with seconds in `Context.time` series.
#### Added
* Built-in indicator Volume Weighted Average Price.
#### Added
* `Context.is_last` and `Context.is_realtime`.
* `in` operator support.
* `lookahead` param to `Context.calc_on`.
#### Added
* Indie language v2 support:
* Pass `ctx` object explicitly everywhere in Indie code.
#### Removed
* Indie language v1 support.
#### Added
* Popup docstrings and autocompleter in the Indie IDE.
#### Added
* `indie.Optional` type.
#### Added
* Built-in indicators: Accumulation/Distribution, Advance/Decline Ratio (Bars), Average Directional Index, Arnaud Legoux Moving Average, Bull Bear Power, Bollinger Bands Width, Commodity Channel Index, Chande Momentum Oscillator, Choppiness Index, Chop Zone, Chande Kroll Stop, Chaikin Money Flow, Coppock Curve, Connors RSI, Donchian Channels, Directional Movement Index, Detrended Price Oscillator, Elders Force Index, Ease of Movement, Fisher Transform, Hull Moving Average, Keltner Channels, Klinger Oscillator, Know Sure Thing, Moving Average Ribbon, Mass Index, McGinley Dynamic, Median, Net Volume, On Balance Volume, Price Oscillator, Price Volume Trend, Rate Of Change, Relative Vigor Index, Relative Volatility Index, SMI Ergodic Indicator, SMI Ergodic Oscillator, Smoothed Moving Average, Triple EMA, TRIX, True Strength Indicator, Ultimate Oscillator, Volume Oscillator, Vortex Indicator, Williams Percent Range, Woodies CCI.
#### Changed
* Better generics support in Indie.
#### Added
* Built-in indicator Volume Moving Average Weighted.
#### Changed
* Renamed package `take_profit` -> `indie`.
#### Added
* Built-in indicator Chaikin Oscillator.
#### Added
* Better type inferring mechanism in the Indie compiler.
#### Changed
* Significant speed-up of indicator calculation.
#### Added
* Built-in indicators: Stochastic Oscillator, Stochastic RSI.
#### Added
* Built-in indicator Bollinger Bands %B.
#### Added
* Built-in indicator Supertrend.
#### Added
* The first chapters of Indie documentation were published on `https://takeprofit.com/docs/indie/`.
#### Added
* Built-in indicators: Average Day Range, Aroon, Average True Range, Awesome Oscillator, Bollinger Bands, Balance of
Power, Double EMA, Exponential Moving Average, Envelope, Ichimoku Cloud, Moving Average Convergence Divergence,
Momentum, Money Flow Index, Relative Strength Index, Simple Moving Average, Williams Alligator, Moving
Average Weighted.
#### Added
* 'Indicators Code Editor' widget was added to the TakeProfit platform. This can be considered as Indie language v1
release.
#### Changed
* On this day the name 'Indie' for the new language was invented.
#### Added
* Explicit typing in the language.
#### Added
* Approximate development start of a new *technical analysis*-oriented language for the TakeProfit platform.
# Built-in indicators
Source: https://takeprofit.com/docs/indie/Code-examples/built-in-indicators
## Accumulation/Distribution
```py Accumulation/Distribution
# indie:lang_version = 5
from indie import indicator, format, plot, color
from indie.algorithms import CumSum, Mfv
@indicator('Accum/Dist', format=format.VOLUME) # Accumulation/Distribution
@plot.line(color=color.OLIVE)
def Main(self):
return CumSum.new(Mfv.new())[0]
```
## Advance/Decline Ratio (Bars)
```py Advance/Decline Ratio (Bars)
# indie:lang_version = 5
from indie import indicator, format, param, level, color, plot, MutSeriesF
from indie.algorithms import Sum
from indie.math import divide
@indicator('ADR_B', format=format.PRICE) # Advance/Decline Ratio (Bars)
@param.int('length', default=9, min=1)
@level(1, line_color=color.GRAY, title='Equality Line')
@plot.line(color=color.BLUE, title='ADR_B')
def Main(self, length):
is_up = (self.close[0] - self.open[0]) >= 0.0
is_down_ints = MutSeriesF.new(0 if is_up else 1)
is_up_ints = MutSeriesF.new(1 if is_up else 0)
down_bars = Sum.new(is_down_ints, length)
up_bars = Sum.new(is_up_ints, length)
return divide(up_bars[0], down_bars[0], up_bars[0])
```
## Arnaud Legoux Moving Average
```py Arnaud Legoux Moving Average
# indie:lang_version = 5
from math import exp, pow
from indie import indicator, param, plot, color
from indie.math import divide
@indicator('ALMA', overlay_main_pane=True) # Arnaud Legoux Moving Average
@param.int('window_size', default=9, min=1, title='Window Size')
@param.float('offset', default=0.85)
@param.float('sigma', default=6.0, min=0.001)
@plot.line(color=color.BLUE)
def Main(self, window_size, offset, sigma):
m = offset * (window_size - 1)
s = window_size / sigma
sum, norm = 0.0, 0.0
for i in range(window_size):
weight = exp(-1 * pow(i - m, 2) / (2 * pow(s, 2)))
norm += weight
sum += self.close[window_size - i - 1] * weight
return divide(sum, norm)
```
## Aroon
```py Aroon
# indie:lang_version = 5
from indie import indicator, format, param, plot, color
from indie.algorithms import SinceLowest, SinceHighest
@indicator('Aroon', format=format.PRICE) # TODO: format=format.PERCENT
@param.int('length', default=14, min=1)
@plot.line(color=color.BLUE, title='Aroon Down')
@plot.line(color=color.YELLOW, title='Aroon Up')
def Main(self, length):
lo_offset = SinceLowest.new(self.low, length)
hi_offset = SinceHighest.new(self.high, length)
down = 100 * (length - lo_offset[0]) / length
up = 100 * (length - hi_offset[0]) / length
return down, up
```
## Average Day Range
```py Average Day Range
# indie:lang_version = 5
from indie import indicator, param, plot, color
from indie.algorithms import Sma
@indicator('ADR') # Average Day Range
@param.int('length', default=14, min=1)
@plot.line(color=color.BLUE)
def Main(self, length):
sma_high = Sma.new(self.high, length)
sma_low = Sma.new(self.low, length)
return sma_high[0] - sma_low[0]
```
## Average Directional Index
```py Average Directional Index
# indie:lang_version = 5
from indie import indicator, format, param, plot, color
from indie.algorithms import Adx
@indicator('ADX', format=format.PRICE) # Average Directional Index
@param.int('adx_len', default=14, min=1, title='ADX Smoothing')
@param.int('di_len', default=14, min=1, title='DI Length')
@plot.line(color=color.RED)
def Main(self, adx_len, di_len):
_, adx, _ = Adx.new(adx_len, di_len)
return adx[0]
```
## Average True Range
```py Average True Range
# indie:lang_version = 5
from indie import indicator, param, plot, color
from indie.algorithms import Atr
@indicator('ATR') # Average True Range
@param.int('length', default=14, min=1)
@param.str('smoothing', default='RMA', options=['RMA', 'SMA', 'EMA', 'WMA'], title='Smoothing')
@plot.line(color=color.RED)
def Main(self, length, smoothing):
return Atr.new(length, smoothing)[0]
```
## Awesome Oscillator
```py Awesome Oscillator
# indie:lang_version = 5
from indie import indicator, plot, color, MutSeriesF
from indie.algorithms import Sma
# TODO: Support palettes of colors in indicators
@indicator('AO') # Awesome Oscillator
@plot.columns()
def Main(self):
ao = MutSeriesF.new(Sma.new(self.hl2, 5)[0] - Sma.new(self.hl2, 34)[0])
d = ao[0] - ao[1]
c = color.MAROON if d <= 0 else color.GREEN
return plot.Columns(ao[0], color=c)
```
## Balance of Power
```py Balance of Power
# indie:lang_version = 5
from indie import indicator, format, plot, color
from indie.math import divide
@indicator('BoP', format=format.PRICE) # Balance of Power
@plot.line(color=color.RED)
def Main(self):
return divide(self.close[0] - self.open[0], self.high[0] - self.low[0])
```
## Bollinger Bands
```py Bollinger Bands
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Bb
@indicator('BB', overlay_main_pane=True) # Bollinger Bands
@param.int('length', default=20, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@param.float('mult', default=2.0, min=0.001, max=50.0, title='StdDev')
@param.int('offset', default=0, min=-500, max=500)
@plot.line('lower', color=color.BLUE, title='Lower')
@plot.line(color=color.RED, title='Basis')
@plot.line('upper', color=color.BLUE, title='Upper')
@plot.fill('lower', 'upper', color=color.AQUA(0.05), title='Background')
def Main(self, length, src, mult, offset):
(lower, middle, upper) = Bb.new(src, length, mult)
return (
plot.Line(lower[0], offset=offset),
plot.Line(middle[0], offset=offset),
plot.Line(upper[0], offset=offset),
plot.Fill(offset=offset),
)
```
## Bollinger Bands %B
```py Bollinger Bands %B
# indie:lang_version = 5
from indie import indicator, format, param, source, band, color, level, plot
from indie.algorithms import Bb
from indie.math import divide
@indicator('BB %B', format=format.PRICE) # Bollinger Bands %B
@param.int('length', default=20, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@param.float('mult', default=2.0, min=0.001, max=50.0, title='StdDev')
@band(0, 1, line_color=color.GRAY, fill_color=color.AQUA(0.1), title='Background')
@level(0.5, line_color=color.GRAY, title='Middle Band')
@plot.line(color=color.AQUA, title='Bollinger Bands %B')
def Main(self, length, src, mult):
(lower, _, upper) = Bb.new(src, length, mult)
return divide(src[0] - lower[0], upper[0] - lower[0])
```
## Bollinger Bands Width
```py Bollinger Bands Width
# indie:lang_version = 5
from indie import indicator, format, param, source, plot, color
from indie.algorithms import Bb
from indie.math import divide
@indicator('BBW', format=format.PRICE) # Bollinger Bands Width
@param.int('length', default=20, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@param.float('mult', default=2.0, min=0.001, max=50.0, title='StdDev')
@plot.line(color=color.TEAL)
def Main(self, length, src, mult):
(lower, middle, upper) = Bb.new(src, length, mult)
return divide(upper[0] - lower[0], middle[0])
```
## Bull Bear Power
```py Bull Bear Power
# indie:lang_version = 5
from indie import indicator, param, plot, color
from indie.algorithms import Ema
@indicator('BBP') # Bull Bear Power
@param.int('length', default=13, min=1)
@plot.line(color=color.BLUE)
def Main(self, length):
bear_power = self.low[0] - Ema.new(self.close, length)[0]
bull_power = self.high[0] - Ema.new(self.close, length)[0]
return bull_power + bear_power
```
## Chaikin Money Flow
```py Chaikin Money Flow
# indie:lang_version = 5
from indie import indicator, format, param, level, color, plot
from indie.algorithms import Sum, Mfv
from indie.math import divide
@indicator('CMF', format=format.PRICE) # Chaikin Money Flow
@param.int('length', default=20, min=1, title='Length')
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.GREEN, title='MF')
def Main(self, length):
mfv_sum = Sum.new(Mfv.new(), length)[0]
vol_sum = Sum.new(self.volume, length)[0]
return divide(mfv_sum, vol_sum)
```
## Chaikin Oscillator
```py Chaikin Oscillator
# indie:lang_version = 5
from indie import indicator, format, param, level, color, plot
from indie.algorithms import CumSum, Mfv, Ema
@indicator('Chaikin Osc', format=format.VOLUME) # Chaikin Oscillator
@param.int('fast_length', default=3, min=1, title='Fast Length')
@param.int('slow_length', default=10, min=1, title='Slow Length')
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.RED, title='Chaikin Oscillator')
def Main(self, fast_length, slow_length):
ad = CumSum.new(Mfv.new())
ch_osc = Ema.new(ad, fast_length)[0] - Ema.new(ad, slow_length)[0]
return ch_osc
```
## Chande Kroll Stop
```py Chande Kroll Stop
# indie:lang_version = 5
from indie import indicator, param, plot, color, MutSeriesF
from indie.algorithms import Atr, Lowest, Highest
@indicator('Chande KS', overlay_main_pane=True) # Chande Kroll Stop
@param.int('p', default=10, min=1)
@param.int('x', default=1, min=1)
@param.int('q', default=9, min=1)
@plot.line(color=color.BLUE, title='Stop Long')
@plot.line(color=color.MAROON, title='Stop Short')
def Main(self, p, x, q):
atr = Atr.new(p)[0]
first_low_stop = MutSeriesF.new(Lowest.new(self.low, p)[0] + x * atr)
first_high_stop = MutSeriesF.new(Highest.new(self.high, p)[0] - x * atr)
stop_long = Lowest.new(first_low_stop, q)
stop_short = Highest.new(first_high_stop, q)
return stop_long[0], stop_short[0]
```
## Chande Momentum Oscillator
```py Chande Momentum Oscillator
# indie:lang_version = 5
from indie import indicator, format, param, source, level, color, plot, MutSeriesF
from indie.algorithms import Change, Sum
from indie.math import divide
@indicator('Chande MO', format=format.PRICE) # Chande Momentum Oscillator
@param.int('length', default=9, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.BLUE, title='Chande MO')
def Main(self, length, src):
momm = Change.new(src)[0]
m1 = momm if momm >= 0 else 0
m2 = 0.0 if momm >= 0 else -momm
sm1 = Sum.new(MutSeriesF.new(m1), length)[0]
sm2 = Sum.new(MutSeriesF.new(m2), length)[0]
return 100 * divide(sm1 - sm2, sm1 + sm2)
```
## Chop Zone
```py Chop Zone
# indie:lang_version = 5
from math import nan, isnan, atan, pi
from indie import indicator, format, plot, color, Color
from indie.algorithms import Highest, Lowest, Ema
from indie.math import divide
@indicator('Chop Zone', format=format.PRICE, precision=0)
@plot.columns()
def Main(self):
color_turquoise = color.rgba(38, 198, 218)
color_dark_green = color.rgba(67, 160, 71)
color_pale_green = color.rgba(165, 214, 167)
color_lime = color.rgba(0, 150, 136)
color_dark_red = color.rgba(213, 0, 0)
color_red = color.rgba(233, 30, 99)
color_orange = color.rgba(255, 109, 0)
color_light_orange = color.rgba(255, 183, 77)
color_yellow = color.rgba(253, 216, 53)
periods = 30
highest_high = Highest.new(self.high, periods)[0]
lowest_low = Lowest.new(self.low, periods)[0]
span = divide(25, highest_high - lowest_low) * lowest_low
ema34 = Ema.new(self.close, 34)
y2_ema34 = divide(ema34[1] - ema34[0], self.hlc3[0]) * span
ema_angle_1 = nan
if not isnan(y2_ema34):
ema_angle_1 = round(180 * atan(abs(y2_ema34)) / pi)
ema_angle = -ema_angle_1 if y2_ema34 > 0 else ema_angle_1
chop_zone_color: Color
if ema_angle >= 5:
chop_zone_color = color_turquoise
elif ema_angle >= 3.57:
chop_zone_color = color_dark_green
elif ema_angle >= 2.14:
chop_zone_color = color_pale_green
elif ema_angle >= 0.71:
chop_zone_color = color_lime
elif ema_angle <= -5:
chop_zone_color = color_dark_red
elif ema_angle <= -3.57:
chop_zone_color = color_red
elif ema_angle <= -2.14:
chop_zone_color = color_orange
elif ema_angle <= -0.71:
chop_zone_color = color_light_orange
else: # ema_angle > -0.71 and ema_angle < 0.71
chop_zone_color = color_yellow
return plot.Columns(1, color=chop_zone_color)
```
## Choppiness Index
```py Choppiness Index
# indie:lang_version = 5
from math import log10
from indie import indicator, format, param, band, color, level, plot
from indie.algorithms import Highest, Lowest, Sum, Atr
from indie.math import divide
@indicator('CHOP', format=format.PRICE) # Choppiness Index
@param.int('length', default=14, min=1)
@param.int('offset', default=0, min=-500, max=500)
@band(38.2, 61.8, line_color=color.GRAY, fill_color=color.AQUA(0.1), title='Background')
@level(50, line_color=color.GRAY(0.5), title='Middle Band')
@plot.line(color=color.BLUE, title='CHOP')
def Main(self, length, offset):
hl = Highest.new(self.high, length)[0] - Lowest.new(self.low, length)[0]
res = 100 * divide(log10(divide(Sum.new(Atr.new(1), length)[0], hl)), log10(length))
return plot.Line(res, offset=offset)
```
## Commodity Channel Index
```py Commodity Channel Index
# indie:lang_version = 5
from indie import indicator, format, param, source, band, color, level, plot
from indie.algorithms import Cci
@indicator('CCI', format=format.PRICE) # Commodity Channel Index
@param.int('length', default=20, min=1)
@param.source('src', default=source.HLC3, title='Source')
@band(-100, 100, line_color=color.GRAY, fill_color=color.AQUA(0.1), title='Background')
@level(0, line_color=color.GRAY(0.5), title='Middle Band')
@plot.line(color=color.BLUE, title='CCI')
def Main(self, length, src):
return Cci.new(src, length)[0]
# TODO: implement smoothing when display.none is supported
```
## Connors RSI
```py Connors RSI
# indie:lang_version = 5
from math import isnan
from indie import indicator, format, param, band, color, level, plot, MutSeriesF
from indie.algorithms import Rsi, PercentRank, Roc
def nan_to_zero(val: float) -> float:
return 0 if isnan(val) else val
@indicator('CRSI', format=format.PRICE) # Connors RSI
@param.int('len_rsi', default=3, min=1, title='RSI Length')
@param.int('len_up_down', default=2, min=1, title='UpDown Length')
@param.int('len_roc', default=100, min=1, title='ROC Length')
@band(30, 70, line_color=color.GRAY, fill_color=color.AQUA(0.1), title='Background')
@level(50, line_color=color.GRAY(0.5), title='Middle Band')
@plot.line(color=color.BLUE, title='CRSI')
def Main(self, len_rsi, len_up_down, len_roc):
is_equal = self.close[0] == self.close[1]
is_growing = self.close[0] > self.close[1]
ud = MutSeriesF.new(0) # why not mut_series(init=0)
if is_growing:
if nan_to_zero(ud[1]) <= 0: # why not equal nan_to_zero(ud)[1]
ud[0] = 1
else:
ud[0] = nan_to_zero(ud[1]) + 1
elif not is_equal:
if nan_to_zero(ud[1]) >= 0:
ud[0] = -1
else:
ud[0] = nan_to_zero(ud[1]) - 1
rsi = Rsi.new(self.close, len_rsi)[0]
ud_rsi = Rsi.new(ud, len_up_down)[0]
pr = PercentRank.new(Roc.new(self.close, 1), len_roc)[0]
return (rsi + ud_rsi + pr) / 3
```
## Coppock Curve
```py Coppock Curve
# indie:lang_version = 5
from indie import indicator, param, plot, color, MutSeriesF
from indie.algorithms import Roc, Wma
@indicator('Coppock') # Coppock Curve
@param.int('wma_length', default=10, min=1, title='WMA Length')
@param.int('long_roc_length', default=14, min=1, title='Long RoC Length')
@param.int('short_roc_length', default=11, min=1, title='Short RoC Length')
@plot.line(color=color.BLUE)
def Main(self, wma_length, long_roc_length, short_roc_length):
l_roc = Roc.new(self.close, long_roc_length)[0]
s_roc = Roc.new(self.close, short_roc_length)[0]
curve = Wma.new(MutSeriesF.new(l_roc + s_roc), wma_length)[0]
return curve
```
## Correlation Coefficient
```py Correlation Coefficient
# indie:lang_version = 5
from indie import indicator, MainContext, sec_context, format, param, source, param_ref, level, color, plot
from indie.algorithms import Corr
@sec_context
@param_ref('source')
def SecContext(self, source):
return source[0]
@indicator('CC', format=format.PRICE) # Correlation Coefficient
@param.str('exchange', default='NASDAQ')
@param.str('ticker', default='GOOG')
@param.source('source', default=source.CLOSE)
@param.int('length', default=20, min=1)
@level(1, line_color=color.GRAY)
@level(0)
@level(-1, line_color=color.GRAY)
@plot.line(color=color.BLUE, title='Correlation')
class Main(MainContext):
def __init__(self, exchange, ticker):
self.ctx_other = self.calc_on(SecContext, exchange=exchange, ticker=ticker)
def calc(self, source, length):
corr = Corr.new(source, self.ctx_other, length)
return corr[0]
```
## Double EMA
```py Double EMA
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Ema
@indicator('DEMA', overlay_main_pane=True) # Double EMA
@param.int('length', default=9, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@plot.line(color=color.GREEN)
def Main(self, length, src):
ema1 = Ema.new(src, length)
ema2 = Ema.new(ema1, length)
return 2 * ema1[0] - ema2[0]
```
## Detrended Price Oscillator
```py Detrended Price Oscillator
# indie:lang_version = 5
from indie import indicator, format, param, level, color, plot
from indie.algorithms import Sma
@indicator('DPO', format=format.PRICE) # Detrended Price Oscillator
@param.int('length', default=21, min=1)
@param.bool('centered', default=False, title='Centered')
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.GREEN, title='Detrended Price Oscillator')
def Main(self, length, centered):
bars_back = length // 2 + 1
ma = Sma.new(self.close, length)
dpo = self.close[bars_back] - ma[0] if centered else self.close[0] - ma[bars_back]
return plot.Line(dpo, offset=-bars_back if centered else 0)
```
## Directional Movement Index
```py Directional Movement Index
# indie:lang_version = 5
from indie import indicator, format, param, plot, color
from indie.algorithms import Adx
@indicator('DMI', format=format.PRICE, precision=4) # Directional Movement Index
@param.int('adx_len', default=14, min=1, title='ADX Smoothing')
@param.int('di_len', default=14, min=1, title='DI Length')
@plot.line(color=color.MAROON, title='-DI')
@plot.line(color=color.RED, title='ADX')
@plot.line(color=color.BLUE, title='+DI')
def Main(self, adx_len, di_len):
minus, adx, plus = Adx.new(adx_len, di_len)
return minus[0], adx[0], plus[0]
```
## Donchian Channels
```py Donchian Channels
# indie:lang_version = 5
from indie import indicator, param, plot, color
from indie.algorithms import Lowest, Highest, Donchian
@indicator('DC', overlay_main_pane=True) # Donchian Channels
@param.int('length', default=20, min=1)
@plot.line('lower', color=color.BLUE, title='Lower')
@plot.line(color=color.RED, title='Basis')
@plot.line('upper', color=color.BLUE, title='Upper')
@plot.fill('lower', 'upper', color=color.AQUA(0.05), title='Background')
def Main(self, length):
lower = Lowest.new(self.low, length)
upper = Highest.new(self.high, length)
basis = Donchian.new(length)
return lower[0], basis[0], upper[0], plot.Fill()
```
## Ease of Movement
```py Ease of Movement
# indie:lang_version = 5
from indie import indicator, format, param, plot, color, MutSeriesF
from indie.algorithms import Change, Sma
from indie.math import divide
@indicator('EOM', format=format.VOLUME) # Ease of Movement
@param.int('length', default=14, min=1)
@param.int('divisor', default=10000, min=1)
@plot.line(color=color.GREEN)
def Main(self, length, divisor):
eom = divisor * Change.new(self.hl2)[0] * divide(self.high[0] - self.low[0], self.volume[0])
return Sma.new(MutSeriesF.new(eom), length)[0]
```
## Elders Force Index
```py Elders Force Index
# indie:lang_version = 5
from indie import indicator, format, param, level, color, plot, MutSeriesF
from indie.algorithms import Change, Ema
@indicator('EFI', format=format.VOLUME) # Elders Force Index
@param.int('length', default=13, min=1)
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.RED, title='Elders Force Index')
def Main(self, length):
efi = Change.new(self.close)[0] * self.volume[0]
return Ema.new(MutSeriesF.new(efi), length)[0]
```
## Exponential Moving Average
```py Exponential Moving Average
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Ema
@indicator('EMA', overlay_main_pane=True) # Moving Average Exponential
@param.int('length', default=9, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@param.int('offset', default=0, min=-500, max=500, title='Offset')
@plot.line(color=color.BLUE)
def Main(self, length, src, offset):
ema = Ema.new(src, length)
return plot.Line(ema[0], offset=offset)
# TODO: implement smoothing when display.none is supported
```
## Envelope
```py Envelope
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Ema, Sma
@indicator('Env', overlay_main_pane=True) # Envelope
@param.int('length', default=20, min=1)
@param.float('percent', default=10.0)
@param.source('src', default=source.CLOSE, title='Source')
@param.bool('exponential', default=False)
@plot.line('lower', color=color.BLUE, title='Lower')
@plot.line('basis', color=color.RED, title='Basis')
@plot.line('upper', color=color.BLUE, title='Upper')
@plot.fill('lower', 'upper', color=color.AQUA(0.05), title='Background')
def Main(self, length, percent, src, exponential):
basis = 0.0
if exponential:
basis = Ema.new(src, length)[0]
else:
basis = Sma.new(src, length)[0]
k = percent / 100.0
upper = basis * (1 + k)
lower = basis * (1 - k)
return lower, basis, upper, plot.Fill()
```
## Fisher Transform
```py Fisher Transform
# indie:lang_version = 5
from math import isnan, nan, log
from indie import indicator, format, param, level, color, plot, MutSeriesF
from indie.algorithms import Highest, Lowest
from indie.math import divide
def nan_to_zero(val: float) -> float:
return 0 if isnan(val) else val
def round(val: float) -> float:
if val > 0.99:
val = 0.999
elif val < -0.99:
val = -0.999
return val
@indicator('Fisher', format=format.PRICE) # Fisher Transform
@param.int('length', default=9, min=1)
@level(-1.5, line_color=color.RED, title='-1.5')
@level(-0.75, line_color=color.GRAY, title='-0.75')
@level(0, line_color=color.RED, title='0')
@level(0.75, line_color=color.GRAY, title='0.75')
@level(1.5, line_color=color.RED, title='1.5')
@plot.line(color=color.BLUE, title='Fisher')
@plot.line(color=color.MAROON, title='Trigger')
def Main(self, length):
high = Highest.new(self.hl2, length)[0]
low = Lowest.new(self.hl2, length)[0]
value = MutSeriesF.new(init=0)
value[0] = round(0.66 * (divide(self.hl2[0] - low, high - low) - 0.5) + \
0.67 * nan_to_zero(value[1]))
fish = MutSeriesF.new(init=nan)
fish[0] = 0.5 * log(divide(1 + value[0], 1 - value[0])) + 0.5 * nan_to_zero(fish[1])
return fish[0], fish[1]
```
## Hull Moving Average
```py Hull Moving Average
# indie:lang_version = 5
from math import floor, sqrt
from indie import indicator, param, source, plot, color, MutSeriesF
from indie.algorithms import Wma
@indicator('HMA', overlay_main_pane=True) # Hull Moving Average
@param.int('length', default=9, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@plot.line(color=color.BLUE)
def Main(self, length, src):
wma_l2 = Wma.new(src, length // 2)[0]
wma_l = Wma.new(src, length)[0]
return Wma.new(MutSeriesF.new(2 * wma_l2 - wma_l), floor(sqrt(length)))[0]
```
## Ichimoku Cloud
```py Ichimoku Cloud
# indie:lang_version = 5
from indie import SeriesF, MutSeriesF, indicator, param, plot, color
from indie.algorithms import Donchian
def mean(price1: SeriesF, price2: SeriesF) -> float:
# TODO: implement @algorithm avg with variable number of arguments in indie.algorithms
return (price1[0] + price2[0]) / 2
# TODO: Add palette of colors
@indicator('Ichimoku', overlay_main_pane=True) # Ichimoku Cloud
@param.int('conversion_periods', default=9, min=1, title='Conversion Line Length')
@param.int('base_periods', default=26, min=1, title='Base Line Length')
@param.int('lagging_span_2_periods', default=52, min=1, title='Leading Span B Length')
@param.int('displacement', default=26, min=1, title='Lagging Span')
@plot.line(color=color.BLUE, title='Conversion Line')
@plot.line(color=color.RED, title='Base Line')
@plot.line(color=color.GREEN, title='Lagging Span')
@plot.line('ls_a', color=color.GREEN(0.6), title='Leading Span A')
@plot.line('ls_b', color=color.RED(0.6), title='Leading Span B')
@plot.fill('ls_a', 'ls_b', title='Background')
def Main(self, conversion_periods, base_periods, lagging_span_2_periods, displacement):
conversion_line = Donchian.new(conversion_periods)
base_line = Donchian.new(base_periods)
lead_line1 = mean(conversion_line, base_line)
lead_line2 = Donchian.new(lagging_span_2_periods)[0]
fill_color = color.GREEN(0.1) if lead_line1 > lead_line2 else color.RED(0.1)
return (
conversion_line[0],
base_line[0],
plot.Line(self.close[0], offset=-displacement + 1),
plot.Line(lead_line1, offset=displacement - 1),
plot.Line(lead_line2, offset=displacement - 1),
plot.Fill(offset=displacement - 1, color=fill_color),
)
```
## Keltner Channels
```py Keltner Channels
# indie:lang_version = 5
from indie import indicator, param, source, plot, color, MutSeriesF
from indie.algorithms import Ma, Tr, Atr, Rma
@indicator('KC', overlay_main_pane=True) # Keltner Channels
@param.int('length', default=20, min=1)
@param.float('mult', default=2.0, title='Multiplier')
@param.source('src', default=source.CLOSE, title='Source')
@param.bool('exp', default=True, title='Use Exponential MA')
@param.str('bands_style', default='Average True Range', title='Bands Style',
options=['Average True Range', 'True Range', 'Range'])
@param.int('atr_length', default=10, min=1, title='ATR Length')
@plot.line('lower', color=color.BLUE, title='Lower')
@plot.line(color=color.BLUE, title='Basis')
@plot.line('upper', color=color.BLUE, title='Upper')
@plot.fill('lower', 'upper', color=color.AQUA(0.05), title='Background')
def Main(self, length, mult, src, exp, bands_style, atr_length):
ma = Ma.new(src, length, 'EMA' if exp else 'SMA')[0]
range_ma = 0.0
if bands_style == 'True Range':
range_ma = Tr.new(True)[0]
elif bands_style == 'Average True Range':
range_ma = Atr.new(atr_length)[0]
else: # bands_style == 'Range'
range_ma = Rma.new(MutSeriesF.new(self.high[0] - self.low[0]), length)[0]
upper = ma + range_ma * mult
lower = ma - range_ma * mult
return lower, ma, upper, plot.Fill()
```
## Klinger Oscillator
```py Klinger Oscillator
# indie:lang_version = 5
from indie import indicator, format, plot, color, MutSeriesF
from indie.algorithms import Change, Ema
@indicator('Klinger Osc', format=format.VOLUME) # Klinger Oscillator
@plot.line(color=color.BLUE, title='KO')
@plot.line(color=color.GREEN, title='Signal')
def Main(self):
sv = MutSeriesF.new(self.volume[0] if Change.new(self.hlc3)[0] >= 0 else -self.volume[0])
kvo = MutSeriesF.new(Ema.new(sv, 34)[0] - Ema.new(sv, 55)[0])
sig = Ema.new(kvo, 13)
return kvo[0], sig[0]
```
## Know Sure Thing
```py Know Sure Thing
# indie:lang_version = 5
from indie import algorithm, MutSeriesF, SeriesF, indicator, format, param, level, color, plot
from indie.algorithms import Sma, Roc
@algorithm
def SmaRoc(self, roc_len: int, sma_len: int) -> SeriesF:
return Sma.new(Roc.new(self.ctx.close, roc_len), sma_len)
@indicator('KST', format=format.PRICE, precision=4) # Know Sure Thing
@param.int('roc_len1', default=10, min=1, title='ROC Length #1')
@param.int('roc_len2', default=15, min=1, title='ROC Length #2')
@param.int('roc_len3', default=20, min=1, title='ROC Length #3')
@param.int('roc_len4', default=30, min=1, title='ROC Length #4')
@param.int('sma_len1', default=10, min=1, title='SMA Length #1')
@param.int('sma_len2', default=10, min=1, title='SMA Length #2')
@param.int('sma_len3', default=10, min=1, title='SMA Length #3')
@param.int('sma_len4', default=15, min=1, title='SMA Length #4')
@param.int('sig_len', default=9, min=1, title='Signal Line Length')
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.GREEN, title='KST')
@plot.line(color=color.RED, title='Signal')
def Main(self, roc_len1, roc_len2, roc_len3, roc_len4, sma_len1, sma_len2, sma_len3, sma_len4, sig_len):
kst = 1 * SmaRoc.new(roc_len1, sma_len1)[0] + \
2 * SmaRoc.new(roc_len2, sma_len2)[0] + \
3 * SmaRoc.new(roc_len3, sma_len3)[0] + \
4 * SmaRoc.new(roc_len4, sma_len4)[0]
sig = Sma.new(MutSeriesF.new(kst), sig_len)[0]
return kst, sig
```
## Least Squares Moving Average
```py Least Squares Moving Average
# indie:lang_version = 5
from indie import indicator, param, source, plot
from indie.algorithms import LinReg
@indicator('LSMA', overlay_main_pane=True) # Least Squares Moving Average
@param.int('length', default=25, min=1)
@param.int('offset', default=0)
@param.source('src', default=source.CLOSE)
@plot.line(title='LSMA')
def Main(self, length, offset, src):
return LinReg.new(src, length, offset)[0]
```
## MA Cross
```py MA Cross
# indie:lang_version = 5
from math import nan
from indie import indicator, param, plot, color
from indie.algorithms import Sma
from indie.math import cross
@indicator('MA Cross', overlay_main_pane=True) # MA Cross
@param.int('short_len', default=9, min=1, title='Short MA Length')
@param.int('long_len', default=21, min=1, title='Long MA Length')
@plot.line(color=color.MAROON, title='Short')
@plot.line(color=color.GREEN, title='Long')
@plot.marker(color=color.BLUE, style=plot.marker_style.CROSS,
position=plot.marker_position.CENTER, size=7, title='MA Cross')
def Main(self, short_len, long_len):
short = Sma.new(self.close, short_len)
long = Sma.new(self.close, long_len)
return short[0], long[0], short[0] if cross(short, long) else nan
```
## Moving Average Ribbon
```py Moving Average Ribbon
# indie:lang_version = 5
from math import nan
from indie import indicator, param, source, plot, color
from indie.algorithms import Ma
@indicator('MA Ribbon', overlay_main_pane=True) # Moving Average Ribbon
@param.bool('ma1', default=True, title='Show MA №1')
@param.str('ma1_type', default='SMA', title='MA №1 Type', options=['SMA', 'EMA', 'SMMA (RMA)', 'WMA', 'VWMA'])
@param.source('ma1_source', default=source.CLOSE, title='MA №1 Source')
@param.int('ma1_length', default=20, min=1, title='MA №1 Length')
@param.bool('ma2', default=True, title='Show MA №2')
@param.str('ma2_type', default='SMA', title='MA №2 Type', options=['SMA', 'EMA', 'SMMA (RMA)', 'WMA', 'VWMA'])
@param.source('ma2_source', default=source.CLOSE, title='MA №2 Source')
@param.int('ma2_length', default=50, min=1, title='MA №2 Length')
@param.bool('ma3', default=True, title='Show MA №3')
@param.str('ma3_type', default='SMA', title='MA №3 Type', options=['SMA', 'EMA', 'SMMA (RMA)', 'WMA', 'VWMA'])
@param.source('ma3_source', default=source.CLOSE, title='MA №3 Source')
@param.int('ma3_length', default=100, min=1, title='MA №3 Length')
@param.bool('ma4', default=True, title='Show MA №4')
@param.str('ma4_type', default='SMA', title='MA №4 Type', options=['SMA', 'EMA', 'SMMA (RMA)', 'WMA', 'VWMA'])
@param.source('ma4_source', default=source.CLOSE, title='MA №4 Source')
@param.int('ma4_length', default=200, min=1, title='MA №4 Length')
@plot.line(color=color.rgba(246, 195, 9), title='MA №1')
@plot.line(color=color.rgba(251, 152, 0), title='MA №2')
@plot.line(color=color.rgba(251, 101, 0), title='MA №3')
@plot.line(color=color.rgba(246, 12, 12), title='MA №4')
def Main(self, ma1, ma1_type, ma1_source, ma1_length, \
ma2, ma2_type, ma2_source, ma2_length, \
ma3, ma3_type, ma3_source, ma3_length, \
ma4, ma4_type, ma4_source, ma4_length):
ma1_val = Ma.new(ma1_source, ma1_length, ma1_type)[0]
ma2_val = Ma.new(ma2_source, ma2_length, ma2_type)[0]
ma3_val = Ma.new(ma3_source, ma3_length, ma3_type)[0]
ma4_val = Ma.new(ma4_source, ma4_length, ma4_type)[0]
return ma1_val if ma1 else nan, \
ma2_val if ma2 else nan, \
ma3_val if ma3 else nan, \
ma4_val if ma4 else nan
```
## Moving Average Convergence Divergence
```py Moving Average Convergence Divergence
# indie:lang_version = 5
from indie import indicator, param, source, level, color, plot, Color
from indie.algorithms import Macd
@indicator('MACD') # Moving Average Convergence Divergence
@param.int('fast_length', default=12, min=1, title='Fast Length')
@param.int('slow_length', default=26, min=1, title='Slow Length')
@param.source('src', default=source.CLOSE, title='Source')
@param.int('signal_length', default=9, min=1, max=50, title='Signal Smoothing')
@param.str('sma_source', default='EMA', title='Oscillator MA Type', options=['SMA', 'EMA'])
@param.str('sma_signal', default='EMA', title='Signal Line MA Type', options=['SMA', 'EMA'])
@level(0, line_color=color.GRAY(0.5))
@plot.columns(title='Histogram')
@plot.line(color=color.BLUE, title='MACD')
@plot.line(color=color.MAROON, title='Signal')
def Main(self, fast_length, slow_length, src, signal_length, sma_source, sma_signal):
macd, signal, hist = Macd.new(src, fast_length, slow_length, signal_length, sma_source, sma_signal)
hist_color: Color
if hist[0] >= 0:
if hist[1] < hist[0]:
hist_color = color.GREEN
else:
hist_color = color.LIME
else:
if hist[1] < hist[0]:
hist_color = color.RED
else:
hist_color = color.MAROON
return (
plot.Columns(hist[0], color=hist_color),
macd[0],
signal[0],
)
```
## Mass Index
```py Mass Index
# indie:lang_version = 5
from indie import indicator, format, param, plot, color, MutSeriesF
from indie.algorithms import Ema, Sum
from indie.math import divide
@indicator('Mass Index', format=format.PRICE)
@param.int('length', default=10, min=1)
@plot.line(color=color.BLUE)
def Main(self, length):
span = MutSeriesF.new(self.high[0] - self.low[0])
ema1 = Ema.new(span, 9)
ema2 = Ema.new(ema1, 9)
return Sum.new(MutSeriesF.new(divide(ema1[0], ema2[0])), length)[0]
```
## McGinley Dynamic
```py McGinley Dynamic
# indie:lang_version = 5
from math import isnan, pow
from indie import indicator, param, plot, color, MutSeriesF
from indie.algorithms import Ema
from indie.math import divide
@indicator('McGinley', overlay_main_pane=True) # McGinley Dynamic
@param.int('length', default=14, min=1)
@plot.line(color=color.BLUE)
def Main(self, length):
mg = MutSeriesF.new(init=0)
if isnan(mg[1]):
mg[0] = Ema.new(self.close, length)[0]
else:
mg[0] = mg[1] + divide(self.close[0] - mg[1], length * pow(divide(self.close[0], mg[1]), 4))
return mg[0]
```
## Median
```py Median
# indie:lang_version = 5
from indie import indicator, param, source, plot, color, MutSeriesF
from indie.algorithms import Median, Atr, Ema
@indicator('Median', overlay_main_pane=True)
@param.source('src', default=source.HL2, title='Source')
@param.int('length', default=3, min=1, title='Median Length')
@param.int('atr_length', default=14, min=1, title='ATR Length')
@param.int('atr_mult', default=2, min=1, title='ATR Multiplier')
@plot.line('ema', color=color.BLUE, title='Median EMA')
@plot.line(color=color.FUCHSIA, title='Lower Band')
@plot.line('median', color=color.RED, line_width=3, title='Median')
@plot.line(color=color.LIME, title='Upper Band')
@plot.fill('median', 'ema', title='Background')
def Main(self, src, length, atr_length, atr_mult):
median = Median.new(src, length)[0]
atr = atr_mult * Atr.new(atr_length)[0]
median_ema = Ema.new(MutSeriesF.new(median), length)[0]
fill_color = color.LIME(0.9) if median > median_ema else color.FUCHSIA(0.9)
return (
median_ema,
median - atr,
median,
median + atr,
plot.Fill(color=fill_color),
)
```
## Momentum
```py Momentum
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Change
@indicator('Mom') # Momentum
@param.int('length', default=10, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@plot.line(color=color.BLUE)
def Main(self, length, src):
return Change.new(src, length)[0]
```
## Money Flow Index
```py Money Flow Index
# indie:lang_version = 5
from indie import indicator, format, param, source, band, color, level, plot
from indie.algorithms import Mfi
@indicator('MFI', format=format.PRICE) # Money Flow Index
@param.int('length', default=14, min=1)
@param.source('src', default=source.HLC3, title='Source')
@band(20, 80, line_color=color.GRAY, fill_color=color.PURPLE(0.1), title='Background')
@level(50, line_color=color.GRAY, title='Middle Band')
@plot.line(color=color.PURPLE, title='MF')
def Main(self, length, src):
return Mfi.new(src, length)[0]
```
## Net Volume
```py Net Volume
# indie:lang_version = 5
from indie import indicator, format, plot, color
from indie.algorithms import NetVolume
@indicator('Net Volume', format=format.VOLUME)
@plot.line(color=color.BLUE)
def Main(self):
return NetVolume.new(self.close)[0]
```
## On Balance Volume
```py On Balance Volume
# indie:lang_version = 5
from indie import indicator, format, plot, color
from indie.algorithms import CumSum, NanToZero, NetVolume
@indicator('OBV', format=format.VOLUME) # On Balance Volume
@plot.line(color=color.BLUE)
def Main(self):
return CumSum.new(NanToZero.new(NetVolume.new(self.close)))[0]
# TODO: implement smoothing when display.none is supported
```
## Parabolic Stop And Reverse
```py Parabolic Stop And Reverse
# indie:lang_version = 5
from indie import indicator, param, plot, color
from indie.algorithms import Sar
@indicator('SAR', overlay_main_pane=True) # Parabolic Stop And Reverse
@param.float('start', default=0.02)
@param.float('increment', default=0.02)
@param.float('maximum', default=0.2)
@plot.marker(style=plot.marker_style.CROSS, color=color.BLUE, title='ParabolicSAR')
def Main(self, start, increment, maximum):
return Sar.new(start, increment, maximum)[0]
```
## Price Oscillator
```py Price Oscillator
# indie:lang_version = 5
from indie import indicator, format, param, source, level, color, plot
from indie.algorithms import Ema, Sma
from indie.math import divide
@indicator('PPO', format=format.PRICE) # Price Oscillator
@param.int('short_len', default=10, min=1, title='Short Length')
@param.int('long_len', default=21, min=1, title='Long Length')
@param.source('src', default=source.CLOSE, title='Source')
@param.bool('exponential', default=False)
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.GREEN, title='OSC')
def Main(self, short_len, long_len, src, exponential):
short, long = 0.0, 0.0
if exponential:
short = Ema.new(src, short_len)[0]
long = Ema.new(src, long_len)[0]
else:
short = Sma.new(src, short_len)[0]
long = Sma.new(src, long_len)[0]
return 100 * divide(short - long, long)
```
## Price Volume Trend
```py Price Volume Trend
# indie:lang_version = 5
from indie import indicator, format, plot, color, MutSeriesF
from indie.algorithms import CumSum, NanToZero, Change
from indie.math import divide
@indicator('PVT', format=format.VOLUME) # Price Volume Trend
@plot.line(color=color.BLUE)
def Main(self):
return CumSum.new(NanToZero.new(MutSeriesF.new(
divide(Change.new(self.close)[0], self.close[1]) * self.volume[0])))[0]
```
## Rate Of Change
```py Rate Of Change
# indie:lang_version = 5
from indie import indicator, format, param, source, level, color, plot
from indie.algorithms import Roc
@indicator('ROC', format=format.PRICE) # Rate Of Change
@param.int('length', default=9, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.BLUE, title='ROC')
def Main(self, length, src):
return Roc.new(src, length)[0]
```
## Relative Vigor Index
```py Relative Vigor Index
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF, indicator, format, param, plot, color
from indie.algorithms import Sum
from indie.math import divide
@algorithm # Symmetrically Weighted Moving Average
def Swma(self, src: SeriesF) -> SeriesF:
return MutSeriesF.new(src[3] / 6 + src[2] / 3 + src[1] / 3 + src[0] / 6)
@indicator('RVGI', format=format.PRICE, precision=4) # Relative Vigor Index
@param.int('length', default=10, min=1)
@param.int('offset', default=0, min=-500, max=500)
@plot.line(color=color.GREEN, title='RVGI')
@plot.line(color=color.RED, title='Signal')
def Main(self, length, offset):
cl_op_sum = Sum.new(Swma.new(MutSeriesF.new(self.close[0] - self.open[0])), length)[0]
hi_lo_sum = Sum.new(Swma.new(MutSeriesF.new(self.high[0] - self.low[0])), length)[0]
rvi = divide(cl_op_sum, hi_lo_sum)
sig = Swma.new(MutSeriesF.new(rvi))[0]
return plot.Line(rvi, offset=offset), plot.Line(sig, offset=offset)
```
## Relative Volatility Index
```py Relative Volatility Index
# indie:lang_version = 5
from math import nan
from indie import indicator, format, param, band, color, level, plot, MutSeriesF
from indie.algorithms import StdDev, Ema, Change, Bb, Ma
from indie.math import divide
@indicator('RVI', format=format.PRICE) # Relative Volatility Index
@param.int('length', default=10, min=1)
@param.int('offset', default=0, min=-500, max=500)
@param.str('ma_type', default='SMA', title='MA Type', options=['SMA', 'Bollinger Bands', 'EMA', 'SMMA (RMA)', 'WMA', 'VWMA'])
@param.int('ma_length', default=14, title='MA Length', min=1)
@param.float('bb_mult', default=2.0, title='BB StdDev', min=0.001, max=50)
@band(20, 80, line_color=color.GRAY, fill_color=color.PURPLE(0.1))
@level(50, line_color=color.GRAY(0.5))
@plot.line(color=color.YELLOW, title='RVI-based MA')
@plot.line(color=color.PURPLE, title='RVI')
@plot.line('bb_lower', color=color.GREEN, title='Lower Bollinger Band')
@plot.line('bb_upper', color=color.GREEN, title='Upper Bollinger Band')
@plot.fill('bb_lower', 'bb_upper', color=color.GREEN(0.1), title='Bollinger Bands Background Fill')
def Main(self, length, offset, ma_type, ma_length, bb_mult):
dev = StdDev.new(self.close, length)[0]
upper = Ema.new(MutSeriesF.new(0 if Change.new(self.close)[0] <= 0 else dev), 14)[0]
lower = Ema.new(MutSeriesF.new(0 if Change.new(self.close)[0] > 0 else dev), 14)[0]
rvi = MutSeriesF.new(100 * divide(upper, upper + lower))
low_value, rvi_ma, high_value = nan, nan, nan
if ma_type == 'Bollinger Bands':
(bb_lower, bb_middle, bb_upper) = Bb.new(rvi, ma_length, bb_mult)
low_value = bb_lower[0]
rvi_ma = bb_middle[0]
high_value = bb_upper[0]
else:
rvi_ma = Ma.new(rvi, ma_length, ma_type)[0]
return (
plot.Line(rvi_ma, offset=offset),
plot.Line(rvi[0], offset=offset),
low_value,
high_value,
plot.Fill(),
)
```
## Relative Strength Index
```py Relative Strength Index
# indie:lang_version = 5
from math import nan
from indie import indicator, format, param, source, band, color, level, plot
from indie.algorithms import Rsi, Ma, StdDev
@indicator('RSI', format=format.PRICE) # Relative Strength Index
@param.int('rsi_length', default=14, title='RSI Length', min=1)
@param.source('src', default=source.CLOSE, title='Source')
@param.str('ma_type', default='SMA', title='MA Type',
options=['SMA', 'Bollinger Bands', 'EMA', 'SMMA (RMA)', 'WMA', 'VWMA'])
@param.int('ma_length', default=14, title='MA Length', min=1)
@param.float('bb_mult', default=2.0, title='BB StdDev', min=0.001, max=50)
@band(30, 70, line_color=color.GRAY, fill_color=color.PURPLE(0.1))
@level(50, line_color=color.GRAY(0.5))
@plot.line(color=color.YELLOW, title='RSI-based MA')
@plot.line(color=color.PURPLE, title='RSI')
@plot.line('bb_lower', color=color.GREEN, title='RSI Lower Band')
@plot.line('bb_upper', color=color.GREEN, title='RSI Upper Band')
@plot.fill('bb_lower', 'bb_upper', color=color.GREEN(0.1), title='Bollinger Bands Background Fill')
def Main(self, rsi_length, src, ma_type, ma_length, bb_mult):
rsi = Rsi.new(src, rsi_length)
is_bb = ma_type == 'Bollinger Bands'
ma_algorithm = 'SMA' if is_bb else ma_type
rsi_ma = Ma.new(rsi, ma_length, ma_algorithm)
std_dev = StdDev.new(rsi, ma_length)
bb_lower = rsi_ma[0] - std_dev[0] * bb_mult if is_bb else nan
bb_upper = rsi_ma[0] + std_dev[0] * bb_mult if is_bb else nan
return rsi_ma[0], rsi[0], bb_lower, bb_upper, plot.Fill()
```
## Simple Moving Average
```py Simple Moving Average
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Sma
@indicator('SMA', overlay_main_pane=True) # Simple Moving Average
@param.int('length', default=9, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@param.int('offset', default=0, min=-500, max=500, title='Offset')
@plot.line(color=color.BLUE)
def Main(self, length, src, offset):
sma = Sma.new(src, length)
return plot.Line(sma[0], offset=offset)
# TODO: implement smoothing when display.none is supported
```
## SMI Ergodic Indicator
```py SMI Ergodic Indicator
# indie:lang_version = 5
from indie import indicator, format, param, plot, color
from indie.algorithms import Tsi, Ema
@indicator('SMII', format=format.PRICE, precision=4) # SMI Ergodic Indicator
@param.int('long_len', default=20, min=1, title='Long Length')
@param.int('short_len', default=5, min=1, title='Short Length')
@param.int('signal_len', default=5, min=1, title='Signal Length')
@plot.line(color=color.BLUE, title='SMI')
@plot.line(color=color.MAROON, title='Signal')
def Main(self, long_len, short_len, signal_len):
tsi = Tsi.new(self.close, long_len, short_len)
return tsi[0], Ema.new(tsi, signal_len)[0]
```
## SMI Ergodic Oscillator
```py SMI Ergodic Oscillator
# indie:lang_version = 5
from indie import indicator, format, param, plot, color
from indie.algorithms import Tsi, Ema
@indicator('SMIO', format=format.PRICE, precision=4) # SMI Ergodic Oscillator
@param.int('long_len', default=20, min=1, title='Long Length')
@param.int('short_len', default=5, min=1, title='Short Length')
@param.int('signal_len', default=5, min=1, title='Signal Length')
@plot.histogram(color=color.RED)
def Main(self, long_len, short_len, signal_len):
tsi = Tsi.new(self.close, long_len, short_len)
return tsi[0] - Ema.new(tsi, signal_len)[0]
```
## Smoothed Moving Average
```py Smoothed Moving Average
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Rma
@indicator('SMMA', overlay_main_pane=True) # Smoothed Moving Average
@param.int('length', default=7, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@plot.line(color=color.PURPLE)
def Main(self, length, src):
return Rma.new(src, length)[0]
```
## Stochastic Oscillator
```py Stochastic Oscillator
# indie:lang_version = 5
from indie import indicator, format, param, band, color, level, plot
from indie.algorithms import Sma, Stoch
@indicator('Stoch', format=format.PRICE) # Stochastic
@param.int('k_length', default=14, min=1, title='Fast K stochastic length')
@param.int('k_smoothing', default=1, min=1, title='Fast K stochastic smoothing')
@param.int('d_smoothing', default=3, min=1, title='Slow D stochastic smoothing')
@band(20, 80, fill_color=color.AQUA(0.1), line_color=color.GRAY, title='Background')
@level(50, line_color=color.GRAY(0.5), title='Middle Band')
@plot.line(color=color.BLUE, title='%K')
@plot.line(color=color.RED, title='%D')
def Main(self, k_length, k_smoothing, d_smoothing):
k = Sma.new(Stoch.new(self.close, self.low, self.high, k_length), k_smoothing)
d = Sma.new(k, d_smoothing)
return k[0], d[0]
```
## Stochastic RSI
```py Stochastic RSI
# indie:lang_version = 5
from indie import indicator, format, param, source, band, color, level, plot
from indie.algorithms import Rsi, Stoch, Sma
@indicator('Stoch RSI', format=format.PRICE) # Stochastic RSI
@param.int('k_smoothing', default=3, min=1, title='Fast K stochastic smoothing')
@param.int('d_smoothing', default=3, min=1, title='Slow D stochastic smoothing')
@param.int('rsi_length', default=14, min=1, title='RSI length')
@param.int('k_length', default=14, min=1, title='Stochastic Length')
@param.source('src', default=source.CLOSE, title='Source')
@band(20, 80, fill_color=color.AQUA(0.1), line_color=color.GRAY, title='Background')
@level(50, line_color=color.GRAY(0.5), title='Middle Band')
@plot.line(color=color.BLUE, title='K')
@plot.line(color=color.RED, title='D')
def Main(self, k_smoothing, d_smoothing, rsi_length, k_length, src):
rsi = Rsi.new(src, rsi_length)
k = Sma.new(Stoch.new(rsi, rsi, rsi, k_length), k_smoothing)
d = Sma.new(k, d_smoothing)
return k[0], d[0]
```
## Supertrend
```py Supertrend
# indie:lang_version = 5
from math import nan
from indie import indicator, param, plot, color
from indie.algorithms import Supertrend
@indicator('Supertrend', overlay_main_pane=True)
@param.int('atr_period', default=10, min=1)
@param.float('factor', default=3.0)
@param.str('ma_algorithm', default='RMA', options=['RMA', 'SMA', 'EMA', 'WMA'])
@plot.line('middle', color=color.GRAY(0.5), title='Body Middle') # TODO: support display.none
@plot.line('down', color=color.RED, title='Down Trend')
@plot.line('up', color=color.GREEN, title='Up Trend')
@plot.fill('down', 'middle', color=color.RED(0.1), title='Down-Middle Fill')
@plot.fill('middle', 'up', color=color.GREEN(0.1), title='Middle-Up Fill')
def Main(self, factor, atr_period, ma_algorithm):
st, direction = Supertrend.new(factor, atr_period, ma_algorithm)
st_down = st[0] if direction[0] > 0 else nan
st_up = st[0] if direction[0] < 0 else nan
middle = (self.open[0] + self.close[0]) / 2
return middle, st_down, st_up, plot.Fill(), plot.Fill()
```
## Triple EMA
```py Triple EMA
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Ema
@indicator('TEMA', overlay_main_pane=True) # Triple EMA
@param.int('length', default=9, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@plot.line(color=color.BLUE)
def Main(self, length, src):
ema1 = Ema.new(src, length)
ema2 = Ema.new(ema1, length)
ema3 = Ema.new(ema2, length)
return 3 * (ema1[0] - ema2[0]) + ema3[0]
```
## TRIX
```py TRIX
# indie:lang_version = 5
from math import log
from indie import indicator, format, param, level, color, plot, MutSeriesF
from indie.algorithms import Change, Ema
@indicator('TRIX', format=format.PRICE)
@param.int('length', default=18, min=1)
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.RED, title='TRIX')
def Main(self, length):
return 10000 * Change.new(Ema.new(Ema.new(Ema.new(MutSeriesF.new(log(self.close[0])), length), length), length))[0]
```
## True Strength Indicator
```py True Strength Indicator
# indie:lang_version = 5
from indie import indicator, format, param, level, color, plot
from indie.algorithms import Tsi, Ema
@indicator('TSI', format=format.PRICE, precision=4) # True Strength Indicator
@param.int('long_len', default=25, min=1, title='Long Length')
@param.int('short_len', default=13, min=1, title='Short Length')
@param.int('signal_len', default=13, min=1, title='Signal Length')
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.BLUE, title='TSI')
@plot.line(color=color.RED, title='Signal')
def Main(self, long_len, short_len, signal_len):
tsi = Tsi.new(self.close, long_len, short_len)
return 100 * tsi[0], 100 * Ema.new(tsi, signal_len)[0]
```
## Ultimate Oscillator
```py Ultimate Oscillator
# indie:lang_version = 5
from indie import indicator, format, param, plot, color
from indie.algorithms import Uo
@indicator('UO', format=format.PRICE) # Ultimate Oscillator
@param.int('fast_len', default=7, min=1, title='Fast Length')
@param.int('middle_len', default=14, min=1, title='Middle Length')
@param.int('slow_len', default=28, min=1, title='Slow Length')
@plot.line(color=color.RED)
def Main(self, fast_len, middle_len, slow_len):
return Uo.new(fast_len, middle_len, slow_len)[0]
```
## Volume Oscillator
```py Volume Oscillator
# indie:lang_version = 5
from indie import indicator, format, param, level, color, plot
from indie.algorithms import Ema
from indie.math import divide
@indicator('Volume Osc', format=format.PRICE) # Volume Oscillator # TODO: format=format.PERCENT
@param.int('short_len', default=5, min=1, title='Short Length')
@param.int('long_len', default=10, min=1, title='Long Length')
@level(0, line_color=color.GRAY, title='Zero')
@plot.line(color=color.BLUE, title='VO')
def Main(self, short_len, long_len):
short = Ema.new(self.volume, short_len)[0]
long = Ema.new(self.volume, long_len)[0]
return 100 * divide(short - long, long)
```
## Vortex Indicator
```py Vortex Indicator
# indie:lang_version = 5
from indie import indicator, format, param, plot, color, MutSeriesF
from indie.algorithms import Sum, Atr
from indie.math import divide
@indicator('VI', format=format.PRICE, precision=4) # Vortex Indicator
@param.int('length', default=14, min=2)
@plot.line(color=color.RED, title='VI -')
@plot.line(color=color.BLUE, title='VI +')
def Main(self, length):
vmm = Sum.new(MutSeriesF.new(abs(self.low[0] - self.high[1])), length)[0]
vmp = Sum.new(MutSeriesF.new(abs(self.high[0] - self.low[1])), length)[0]
satr = Sum.new(Atr.new(1), length)[0]
vim = divide(vmm, satr)
vip = divide(vmp, satr)
return vim, vip
```
## Volume Weighted Average Price
```py Volume Weighted Average Price
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Vwap
@indicator('VWAP', overlay_main_pane=True) # Volume Weighted Average Price
@param.source('src', default=source.HLC3, title='Source')
# TODO: add Earnings, Dividends, Splits
@param.str('anchor', default='Session', options=['Session', 'Week', 'Month', 'Year'], title='Anchor')
@param.int('offset', default=0, min=-500, max=500, title='Offset')
@plot.line('vwap', title='VWAP', color=color.BLUE)
@plot.line('upper', title='Upper band', color=color.GREEN)
@plot.line('lower', title='Lower band', color=color.GREEN)
@plot.fill('upper', 'lower', color=color.GREEN(0.1), title='Background')
def Main(self, src, anchor, offset):
std_dev_mult = 1.0
main_line, upper, lower = Vwap.new(src, anchor, std_dev_mult)
return (
plot.Line(main_line[0], offset=offset),
plot.Line(upper[0], offset=offset),
plot.Line(lower[0], offset=offset),
plot.Fill(offset=offset),
)
```
## Volume Moving Average Weighted
```py Volume Moving Average Weighted
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Vwma
@indicator('VWMA', overlay_main_pane=True) # Volume Weighted Moving Average
@param.int('length', default=20, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@param.int('offset', default=0, min=-500, max=500, title='Offset')
@plot.line(color=color.BLUE)
def Main(self, length, src, offset):
result = Vwma.new(src, length)
return plot.Line(result[0], offset=offset)
```
## Williams Alligator
```py Williams Alligator
# indie:lang_version = 5
from indie import indicator, param, plot, color
from indie.algorithms import Rma
@indicator('Alligator', overlay_main_pane=True) # Williams Alligator
@param.int('jaw_period', default=13, min=1, title='Jaw Period')
@param.int('teeth_period', default=8, min=1, title='Teeth Period')
@param.int('lips_period', default=5, min=1, title='Lips Period')
@param.int('jaw_offset', default=8, min=1, title='Jaw Offset')
@param.int('teeth_offset', default=5, min=1, title='Teeth Offset')
@param.int('lips_offset', default=3, min=1, title='Lips Offset')
@plot.line(color=color.BLUE, title='Jaw')
@plot.line(color=color.RED, title='Teeth')
@plot.line(color=color.GREEN, title='Lips')
def Main(self, jaw_period, teeth_period, lips_period, jaw_offset, teeth_offset, lips_offset):
jaw = Rma.new(self.hl2, jaw_period)
teeth = Rma.new(self.hl2, teeth_period)
lips = Rma.new(self.hl2, lips_period)
return (
plot.Line(jaw[0], offset=jaw_offset),
plot.Line(teeth[0], offset=teeth_offset),
plot.Line(lips[0], offset=lips_offset),
)
```
## Williams Percent Range
```py Williams Percent Range
# indie:lang_version = 5
from indie import indicator, format, param, source, band, color, level, line_style, plot
from indie.algorithms import Highest, Lowest
from indie.math import divide
@indicator('Williams %R', format=format.PRICE) # Williams Percent Range
@param.int('length', default=14, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@band(-20, -80, line_color=color.GRAY, fill_color=color.PURPLE(0.1), title='Background')
@level(-50, line_color=color.GRAY, line_style=line_style.DOTTED, title='Middle Level')
@plot.line(color=color.PURPLE, title='%R')
def Main(self, length, src):
max = Highest.new(self.high, length)[0]
min = Lowest.new(self.low, length)[0]
return 100 * divide(src[0] - max, max - min)
```
## Moving Average Weighted
```py Moving Average Weighted
# indie:lang_version = 5
from indie import indicator, param, source, plot, color
from indie.algorithms import Wma
@indicator('WMA', overlay_main_pane=True) # Weighted Moving Average
@param.int('length', default=9, min=1)
@param.source('src', default=source.CLOSE, title='Source')
@param.int('offset', default=0, min=-500, max=500, title='Offset')
@plot.line(color=color.BLUE)
def Main(self, length, src, offset):
result = Wma.new(src, length)
return plot.Line(result[0], offset=offset)
```
## Woodies CCI
```py Woodies CCI
# indie:lang_version = 5
from indie import indicator, param, level, color, line_style, plot, Color
from indie.algorithms import Cci
@indicator('Woodies CCI')
@param.int('cci_turbo_len', default=6, min=3, max=14, title='CCI Turbo Length')
@param.int('cci_14_len', default=14, min=7, max=20, title='CCI 14 Length')
@level(-100, line_color=color.GRAY, line_style=line_style.DOTTED, title='Minus Line')
@level(0, line_color=color.GRAY, line_style=line_style.SOLID, title='Zero Line')
@level(100, line_color=color.GRAY, line_style=line_style.DOTTED, title='Hundred Line')
@plot.histogram(title='CCI Turbo Histogram')
@plot.line(color=color.GREEN, title='CCI Turbo')
@plot.line(color=color.RED, title='CCI 14')
def Main(self, cci_turbo_len, cci_14_len):
cci_turbo = Cci.new(self.close, cci_turbo_len)
cci_14 = Cci.new(self.close, cci_14_len)
last_5_down = cci_14[5] < 0 and cci_14[4] < 0 and cci_14[3] < 0 and cci_14[2] < 0 and cci_14[1] < 0
last_5_up = cci_14[5] > 0 and cci_14[4] > 0 and cci_14[3] > 0 and cci_14[2] > 0 and cci_14[1] > 0
hist_color: Color
if last_5_up:
hist_color = color.GREEN
elif last_5_down:
hist_color = color.RED
elif cci_14[0] < 0:
hist_color = color.GREEN
else:
hist_color = color.RED
return plot.Histogram(cci_14[0], color=hist_color), cci_turbo[0], cci_14[0]
```
# null
Source: https://takeprofit.com/docs/indie/Code-examples/educational-indicators
## SMA algorithm that accepts 'series' length
Indie’s standard `indie.algorithms.Sma` algorithm has a length parameter which cannot be dynamically changed. Its common usage looks like this: `Sma.new(self.close, length=12)`, where the `length` parameter is typically a literal constant. While it is possible for the `length` to be a variable calculated at the time of indicator initialization or even during calculation over bars/candles, the general rule that should not be broken is as follows: once set, the value of the `length` parameter should not change. Otherwise, the algorithm breaks internally and starts giving inaccurate results\*.
Sometimes, greater flexibility is needed. Fortunately, there is a way to achieve this, and this indicator with `MySma` algorithm demonstrates it. The algorithm is based on properties derived from prefix sums. Let’s look at an example to see how it works. Suppose we have a source series of values, src, like this:
`src = …, 2, 7, 5, 4, 3, 9, 6`
Think of this series as a series of close prices of some instrument on a chart. The last (i.e., current) value of this series is `6`, which is accessed in Indie with the expression `src[0]`.
To calculate the SMA with a `length` period, we simply divide the sum of `length` elements by the `length` value. The sum calculation seems straightforward, but it can be inefficient. For example, `sum(src, length=3)` is calculated as `3 + 9 + 6 = 18`. This calculation is CPU-intensive, and the larger the `length` value, the more computationally expensive it becomes (the time complexity of this calculation is linear). This isn’t a big issue if the `length` is constant. However, consider a use case where `length` may vary from 2 to 300, and the size of the src series is around 20,000 bars, requiring SMA (and thus sum) calculations at every bar of this dataset. That would involve a lot of sum operations.
If we use prefix sums, which in Indie can be calculated with a `cs = CumSum.new(src, length)` statement, we can calculate sums in constant time (which is faster):
`cs = …, 2, 9, 14, 18, 21, 30, 36`
Calculation of any sum with any length using the cs series is as simple as subtracting two numbers. For example, sum(src, length=3) = cs\[0] - cs\[3] = 36 - 18 = 18. Let’s calculate sums with a few different lengths:
* `sum(src, length=4) = cs[0] - cs[4] = 36 - 14 = 22`, which is the same as `4 + 3 + 9 + 6 = 22`
* `sum(src, length=5) = cs[0] - cs[5] = 36 - 9 = 27`, which is the same as `5 + 4 + 3 + 9 + 6 = 27`
and so on. The general formula here is:
`sum(src, length) = cs[0] - cs[length]`
In this indicator, there are three SMA plot lines:
* The thin green and thin red lines both use the `indie.algorithm.Sma` from the standard library. They use different but constant `length` parameters: `short_len` and `long_len`. These two plots serve as references with which we compare the third plot.
* The thick light blue line uses the `MySma` algorithm described above, which is based on the prefix sums approach. MySma can accept a 'series' length, and depending on runtime conditions, either `short_len` or `long_len` is passed to it.
We see that the blue line is perfectly aligned with one of the two fixed-length SMA plots, proving its correctness.
This approach can be effectively used not only in the SMA algorithm but in any similar algorithm that can be calculated with the help of prefix sums or derivatives of SMA (like double-SMA and so on).
P. S. This is true as of Indie v4.
```py SMA algorithm that accepts 'series' length
# indie:lang_version = 5
from indie import (
indicator, MutSeriesF, algorithm, SeriesF, plot,
color, param, line_style)
from indie.algorithms import CumSum, Sma
@algorithm
def MySum(self, src: SeriesF, length: int) -> SeriesF:
cs = CumSum.new(src)
return MutSeriesF.new(cs[0] - cs[length])
@algorithm
def MySma(self, src: SeriesF, length: int) -> SeriesF:
s = MySum.new(src, length)
return MutSeriesF.new(s[0] / length)
@indicator("Sma with 'series' length", overlay_main_pane=True)
@param.int('short_len', default=12)
@param.int('long_len', default=24)
@plot.line(color=color.BLUE(alpha=0.65), line_width=7)
@plot.line(color=color.RED)
@plot.line(color=color.GREEN)
def Main(self, short_len, long_len):
# The long and short `Sma`s are calculated here with the algorithm
# from the `indie.algorithms` standard library, they accept only
# non-series lengths and they are plotted to be a reference that
# proves that MySma gives correct results.
short_sma = Sma.new(self.high, short_len)
long_sma = Sma.new(self.high, long_len)
length = short_len
if long_sma[0] >= short_sma[0]:
length = long_len
# So, strictly speaking, `length` is not a series, but just a number.
# But it is kinda series, because it may have different values on different bars.
# NOTE: If you need a truly series length, wrap it with `MutSeriesF.new(length)`.
return (
MySma.new(self.high, length)[0], # Do not use indie.algorithms.Sma here,
# because `length` is not constant over
# different bars. You may try and see how
# indicator starts giving bad results.
short_sma[0],
long_sma[0],
)
```
## Green/Red Bar Counts - usage example of indie.MutSeries\[T] generic class
Indie includes generic series types: `indie.Series[T]` and `indie.MutSeries[T]`. The float-types `indie.SeriesF` and `indie.MutSeriesF` are still available as aliases for `indie.Series[float]` and `indie.MutSeries[float]`, respectively.
The "Green/Red Bar Counts" indicator demonstrates the usage of the new generic class `indie.MutSeries[T]`, which is instantiated with `T` as the `int` type. The generic type parameter `T` can be any (well, almost any) Indie type, such as `bool`, `str`, etc.
```py Green/Red Bar Counts - usage example of indie.MutSeries[T] generic class
# indie:lang_version = 5
import math
from indie import indicator, MutSeries, Context, plot, color
def is_green_bar(ctx: Context) -> bool:
return ctx.close[0] >= ctx.open[0]
@indicator('Green/Red Bar Counts')
@plot.steps(color=color.GREEN)
@plot.steps(color=color.RED)
def Main(self):
# `indie.MutSeries[T]` is a generic class,
# `T` can be `float`, `int`, `bool`, `str`, etc.
green_count = MutSeries[int].new(0)
red_count = MutSeries[int].new(0)
if is_green_bar(self):
green_count[0] = green_count[1] + 1
red_count[0] = 0
else:
green_count[0] = 0
red_count[0] = red_count[1] - 1
return green_count[0], red_count[0]
```
## Sma-Ema Crossover - usage example of indie.Var\[T]
The `indie.Var[T]` container functions similarly to `indie.MutSeries[T]`, but it has a single-value history depth, making it ideal for storing and updating the current state without accumulating historical values. Although `indie.Var[T]` does not store historical values, it differs significantly from a primitive field of type `T` of an Algorithm/Context or a global variable. The key difference lies in its behavior during real-time calculations. `indie.Var[T]` retains only the values set on closing bar updates, reverting to the previous value before each intrabar update.
The "SMA-EMA Crossover" indicator demonstrates the use of `indie.Var[T]` through the algorithm CrossoverWithVar, which detects and retains values on specific crossover events. It also includes the algorithm CrossoverWithSeries to illustrate how to achieve the same result without using `indie.Var[T]`.
```py Sma-Ema Crossover - usage example of indie.Var[T]
# Copyright (c) 2024 @TakeProfit. All rights reserved.
# This work is licensed under the MIT License.
# For a copy, see .
# indie:lang_version = 5
from indie import indicator, Var, plot, MutSeriesF, SeriesF, color, algorithm
from indie.algorithms import Sma, Ema
@algorithm
def CrossoverWithVar(self, s1: SeriesF, s2: SeriesF) -> float:
my_var = Var[float].new(0)
if s1[1] > s2[1] and s1[0] < s2[0]:
my_var.set(s1[0])
return my_var.get()
# Note: this function does the same thing but using MutSeriesF
@algorithm
def CrossoverWithSeries(self, s1: SeriesF, s2: SeriesF) -> float:
my_ser = MutSeriesF.new(init=0)
if s1[1] > s2[1] and s1[0] < s2[0]:
my_ser[0] = s1[0]
return my_ser[0]
@indicator('Sma-Ema Crossover', overlay_main_pane=True)
@plot.line(color=color.MAROON)
@plot.line(color=color.LIME)
@plot.line(color=color.BLUE, line_width=2)
def Main(self):
sma = Sma.new(self.close, 5)
ema = Ema.new(self.close, 5)
return sma[0], ema[0], CrossoverWithVar.new(sma, ema)
```
## Green/Red Bar Count - usage example of indie.Var\[T]
This update of "Green/Red Bar Counts" indicator showcases the `indie.Var[T]` container usage.
In this implementation:
* State Tracking: The `indie.Var[T]` container counts consecutive green (up) or red (down) bars without retaining any history. `indie.Var[T]` is ideal here since it efficiently holds only the most recent value, unlike indie.MutSeries\[T], which maintains a historical sequence of values.
### Why Use indie.Var Instead of a Simple Float or Integer?
Unlike using a single `float` or `int`, `indie.Var` is fully compatible with Indie’s series-based environment, where values update bar by bar. Plain variables would reset on each new bar calculation, causing them to lose their previous state. Moreover, `indie.Var` ensures that values persist correctly in both historical and real-time data. A simple local number variable would reset or lack the ability to update accurately in real-time, making it unsuitable for cumulative calculations. In contrast, indie.Var provides stable, consistent updates across all bars.
### Key Differences with the Previous Version: General Transformation from `MutSeries` to `Var`
In cases where only the latest value is required without retaining historical data, you can convert code from indie.MutSeries to indie.Var by following these general rules:
1. Replace `MutSeries.new()` with `Var.new()`:
`my_var = Var[float].new(0) # instead of my_series = MutSeries[float].new(0)`
2. Use `.get()` and `.set()` instead of indexing:
`var_value = my_var.get() # instead of series_value = my_series[0]`
`my_var.set(new_value) # instead of my_series[0] = new_value`
```py Green/Red Bar Count - usage example of indie.Var[T]
# Copyright (c) 2024 @TakeProfit. All rights reserved.
# This work is licensed under the MIT License.
# For a copy, see .
# indie:lang_version = 5
from indie import indicator, Var, Context, plot, color
def is_green_bar(ctx: Context) -> bool:
return ctx.close[0] >= ctx.open[0]
@indicator('Green/Red Bar Counts')
@plot.steps(color=color.GREEN)
@plot.steps(color=color.RED)
def Main(self):
# `indie.Var[T]` is a generic class,
# `T` can be `float`, `int`, `bool`, `str`, etc.
green_count = Var[int].new(0)
red_count = Var[int].new(0)
if is_green_bar(self):
green_count.set(green_count.get() + 1)
red_count.set(0)
else:
green_count.set(0)
red_count.set(red_count.get() - 1)
return green_count.get(), red_count.get()
```
## Median Algorithm (written with Indie v4 classes)
This is an example of an Indie algorithm that uses class syntax, introduced in the language since version 4.
The Median class of this indicator inherits from the `indie.Algorithm` base class. It has two methods: the `__init__` constructor and `calc`. It is essential that the `__init__` constructor is executed only once during the creation of the indicator. This makes it a good location to create all objects that hold the algorithm's state, ensuring these objects do not lose their data when a candle update arrives (triggering the calc method). The stateful objects (fields) are:
* `self._sorted_vals: list[float]` - A list of the last length values of the input series src. The algorithm keeps those values ordered.
* `self._prev_src_val: float` - The previous value of the last element in the src series.
* `self._bar_count: int` - A counter for bars that we use to detect when a new bar arrives.
The main idea of this Median algorithm is to maintain a sliding window of the last `length` values of the src series and keep these values in sorted order. With such an array, the median is easily calculated as the value in the middle of it.
```py Median Algorithm (written with Indie v4 classes)
# indie:lang_version = 5
import math
from indie import indicator, Algorithm, Context, SeriesF, MutSeriesF, plot, color, param
def swap(a: list[float], i: int, j: int) -> None:
tmp = a[i]
a[i] = a[j]
a[j] = tmp
# The main idea of this algorithm is to have a sliding window
# of `length` last values of `src` series and keep them in a sorted order.
# Having such an array, the median is easily calculated as the value
# in the middle of such an array.
class Median(Algorithm):
def __init__(self, ctx: Context):
super().__init__(ctx)
self._sorted_vals: list[float] = []
self._prev_src_val = math.nan
self._bar_count = 0
def calc(self, src: SeriesF, length: int) -> SeriesF:
# TODO: Need self.ctx.is_new_bar here
is_new_bar = self._bar_count != len(src)
self._bar_count = len(src)
# First we search in our sorted array for an index where
# the new element will be inserted. We add new element at position
# of some existing element which is need to leave the array anyway
insert_index = -1
if len(self._sorted_vals) == length or not is_new_bar:
val_to_remove = math.nan
if not is_new_bar:
val_to_remove = self._prev_src_val
else:
val_to_remove = src[length]
for i in range(len(self._sorted_vals)):
val = self._sorted_vals[i]
if val == val_to_remove:
insert_index = i
break
else:
self._sorted_vals.append(math.nan)
insert_index = len(self._sorted_vals) - 1
# Insert the new element in our sorted array.
# After this line the sorted order could be broken (most likely it is)
self._sorted_vals[insert_index] = self._prev_src_val = src[0]
# Restore sorted order in our array
while insert_index > 0 and self._sorted_vals[insert_index - 1] > self._sorted_vals[insert_index]:
swap(self._sorted_vals, insert_index, insert_index - 1)
insert_index -= 1
while insert_index < len(self._sorted_vals) - 1 and self._sorted_vals[insert_index] > self._sorted_vals[insert_index + 1]:
swap(self._sorted_vals, insert_index, insert_index + 1)
insert_index += 1
# Find the median value
res = math.nan
if len(self._sorted_vals) == length:
if length % 2 == 1:
# Odd number of elements, e.g. [1, 3, 5] so the median is 3
res = self._sorted_vals[(length - 1) // 2]
else:
# Even number of elements, e.g. [1, 3, 5, 7]
# so the median is (3 + 5) / 2 = 8
mid_index = (length - 1) // 2
left = self._sorted_vals[mid_index]
right = self._sorted_vals[mid_index + 1]
res = (left + right) / 2
return MutSeriesF.new(res)
@indicator('Median', overlay_main_pane=True)
@param.int('length', default=10)
@plot.line(color=color.WHITE)
def Main(self, length):
return Median.new(self.close, length)[0]
```
## Custom VWAP - usage example of indie.Schedule class
The "Custom VWAP" indicator demonstrates the usage of the `Schedule` class. If we don’t want to reset VWAP at the start of each new default trading day (using the 'Session' option of the anchor parameter), we can create a custom schedule to define the reset time.
For example, by default, the VWAP reset time for 'BTC/USDT' is at 00:00 UTC. However, we may want to change this reset time to 00:00 in our chosen timezone (e.g., 'America/New\_York' for this indicator).
Key Points:
* The custom schedule is defined in the `__init__` function because creating it on each bar in the `Context.calc` function is resource-inefficient. Alternatively, the `Context.pre_calc` function can be used for schedule definition if we need to access data from `self.info` or `self.trading_session`.
* The is\_same\_period method (for both `Schedule` and `Session` options) is used to detect whether two timestamps belong to the same schedule period or fall on different days.
```py Custom VWAP - usage example of indie.Schedule class
# Copyright (c) 2024 @TakeProfit. All rights reserved.
# This work is licensed under the MIT License.
# For a copy, see .
# indie:lang_version = 5
from math import sqrt
from datetime import datetime, time
from indie import algorithm, SeriesF, MutSeriesF, Var, Optional, IndieError, MainContext, plot
from indie import indicator, param, source, plot, color
from indie.schedule import Schedule, ScheduleRule
@algorithm
def Vwap(self, src: SeriesF, anchor: str, std_dev_mult: float, schedule: Optional[Schedule] = None) -> tuple[SeriesF, SeriesF, SeriesF]:
'''
Custom Volume Weighted Average Price
anchor can be 'Session', 'Day', 'Week', 'Month', 'Year', 'Schedule'
'''
cum_weighted_price = Var[float].new(0)
cum_volume = Var[float].new(0)
vwap_sum = Var[float].new(0)
vwap_count = Var[int].new(0)
vwap_dev_squares = Var[float].new(0)
current_datetime = datetime.utcfromtimestamp(self.ctx.time[0])
prev_datetime = datetime.utcfromtimestamp(self.ctx.time.get(1, 0))
need_reset = False
if anchor == 'Schedule' and schedule is None:
raise IndieError("Schedule parameter cannot be None when anchor is set to 'Schedule'")
if anchor == 'Schedule' and \
not schedule.value().is_same_period(self.ctx.time[0], self.ctx.time.get(1, 0)):
need_reset = True
if anchor == 'Session' and \
not self.ctx.trading_session.is_same_period(self.ctx.time[0], self.ctx.time.get(1, 0)):
need_reset = True
if anchor == 'Day' and (current_datetime.day != prev_datetime.day or
(current_datetime-prev_datetime).days >= 1):
need_reset = True
elif anchor == 'Week' and ((current_datetime.weekday() == 0 and prev_datetime.weekday() != 0) or
(current_datetime-prev_datetime).days >= 7):
need_reset = True
elif anchor == 'Month' and (current_datetime.month != prev_datetime.month or
(current_datetime-prev_datetime).days >= 31):
need_reset = True
elif anchor == 'Year' and current_datetime.year != prev_datetime.year:
need_reset = True
if need_reset:
cum_weighted_price.set(0)
cum_volume.set(0)
vwap_sum.set(0)
vwap_count.set(0)
vwap_dev_squares.set(0)
cum_weighted_price.set(cum_weighted_price.get() + src[0] * self.ctx.volume[0])
cum_volume.set(cum_volume.get() + self.ctx.volume[0])
vwap_value = cum_weighted_price.get() / cum_volume.get()
vwap_sum.set(vwap_sum.get() + vwap_value)
vwap_count.set(vwap_count.get() + 1)
vwap_avg = vwap_sum.get() / vwap_count.get()
vwap_dev_squares.set(vwap_dev_squares.get() + (vwap_value - vwap_avg) ** 2)
vwap_std_dev = sqrt(vwap_dev_squares.get() / vwap_count.get())
std_dev = std_dev_mult * vwap_std_dev
lower = MutSeriesF.new(vwap_value - std_dev)
upper = MutSeriesF.new(vwap_value + std_dev)
return MutSeriesF.new(vwap_value), upper, lower
@indicator('Custom VWAP', overlay_main_pane=True) # Volume Weighted Average Price
@param.source('src', default=source.HLC3, title='Source')
@param.str('anchor', default='Schedule', options=['Session', 'Day', 'Week', 'Month', 'Year', 'Schedule'], title='Anchor')
@param.int('offset', default=0, min=-500, max=500, title='Offset')
@plot.line('vwap', title='VWAP', color=color.BLUE)
@plot.line('upper', title='Upper band', color=color.GREEN)
@plot.line('lower', title='Lower band', color=color.GREEN)
@plot.fill('upper', 'lower', color=color.GREEN(0.1), title='Background')
class Main(MainContext):
def __init__(self, src, anchor, offset):
rule = ScheduleRule(start=time(hour=0), end=time(hour=0)) # 24-hour rule
self.schedule = Schedule(rules=[rule], timezone='America/New_York')
self.src = src
self.anchor = anchor
self.offset = offset
def calc(self):
std_dev_mult = 1.0
main_line, upper, lower = Vwap.new(self.src, self.anchor, std_dev_mult, self.schedule)
return (
plot.Line(main_line[0], offset=self.offset),
plot.Line(upper[0], offset=self.offset),
plot.Line(lower[0], offset=self.offset),
plot.Fill(),
)
```
## Volume spike marker - usage example of Markers
This indicator highlights bars where the trading volume significantly exceeds the recent average. A text marker is plotted above the bar if the current volume is more than twice the 20-bar moving average. It's a simple tool to help spot unusual activity and potential breakout points.
Markers are visual elements that allow you to highlight important moments on the chart by displaying icons, shapes, or text as part of your indicator.
Using markers is just as easy as other plots, you need to declare them in decorators `@plot.marker(...)` and return the corresponding value `plot.Marker(...)` from the Main function. You can use different styles, colors, and sizes of markers, and you can display different text.
Let's take a closer look at the available options in decalaration decorator:
```py
@plot.marker(
# you can choose some available named color or set cutom rgba
color=color.YELLOW,
# CIRCLE/CROSS - just markers, LABEL - text callout, NONE - invisible marker
style=plot.marker_style.LABEL,
# to avoid blocking important parts of the graph, the marker can be shifted relative to the value
position=plot.marker_position.ABOVE,
# the size in some relative units is from 1 to 7
size=3,
# a title to display in the UI, like any plot
title='High volume')
```
And how to return value:
```py
return plot.Marker(
# position of the marker
value=self.high[0] if spike else nan,
# text of marker on current bar
text='Vol: ' + str(self.volume[0]),
# if you want to color the markers in runtime, each one has its own color
# color=...,
# time shifting, like any plot
# offset=...,
)
```
Full code:
```py Volume spike marker - usage example of Markers
# Copyright (c) 2024 @TakeProfit. All rights reserved.
# This work is licensed under the MIT License.
# For a copy, see .
# indie:lang_version = 5
from math import nan
from indie import indicator, param, plot, color
from indie.algorithms import Sma
@indicator('Volume spike marker', overlay_main_pane=True) # MA Cross
@param.int('volume_ma_len', default=20, min=1, title='Volume MA Length')
@param.float('spike_coef', default=2.0, min=1.0, max=1000.0, title='Spike coefficient')
@plot.marker(color=color.YELLOW, style=plot.marker_style.LABEL,
position=plot.marker_position.ABOVE, size=3, title='High volume')
def Main(self, volume_ma_len, spike_coef):
volume_ma = Sma.new(self.volume, volume_ma_len)
spike = self.volume[0] > volume_ma[0] * spike_coef
return plot.Marker(
value=self.high[0] if spike else nan,
text='Vol: ' + str(self.volume[0]),
)
```
## Different types of markers - yet another example of Markers usage
Let's look at another indicator that draws several series of markers of different shapes and colors.
Full code:
```py Different types of markers - yet another example of Markers usage
# Copyright (c) 2024 @TakeProfit. All rights reserved.
# This work is licensed under the MIT License.
# For a copy, see .
# indie:lang_version = 5
from math import sin, pi, nan
from indie import indicator, plot, color
from indie.plot import MarkerDisplayOptions
from indie.algorithms import Highest, Lowest, Sma
@indicator('Markers', overlay_main_pane=True)
@plot.marker(style=plot.marker_style.CROSS)
@plot.marker(style=plot.marker_style.CIRCLE, color=color.AQUA)
@plot.marker(style=plot.marker_style.LABEL, size=7)
def Main(self):
highest = Highest.new(self.high, 100)
lowest = Lowest.new(self.low, 100)
magnitude = highest[0] - lowest[0]
sma = Sma.new(self.close, 100)
r = int(255 * abs(sin(self.bar_index / 10 + 0)))
g = int(255 * abs(sin(self.bar_index / 10 + 0.5)))
b = int(255 * abs(sin(self.bar_index / 10 + 2)))
return (
plot.Marker(self.close[0] + magnitude * 1.5, color=color.rgba(r, g, b)),
sin(self.bar_index / 5) * magnitude + sma[0] if self.bar_index % 3 == 0 else nan,
plot.Marker(self.close[0] + magnitude / 2.0 if self.bar_index % 20 == 0 else nan, text='WOW' + str(self.bar_index % 3 + 1)),
)
```
As before, we need to declare several series of markers in the decorators:
```py
@plot.marker(style=plot.marker_style.CROSS)
@plot.marker(style=plot.marker_style.CIRCLE, color=color.AQUA)
@plot.marker(style=plot.marker_style.LABEL, size=7)
```
And return their values.
Please note that if you do not need to configure the marker in runtime, you can set all the settings in the decorator and return `float`, the type will be implicitly converted to `plot.Marker`:
```py
return (
...,
sin(self.bar_index / 5) * magnitude + sma[0] if self.bar_index % 3 == 0 else nan,
...,
)
```
But if you need to select a color or text in runtime, you can return the `plot.Maker` object:
```py
return (
plot.Marker(self.close[0] + magnitude * 1.5, color=color.rgba(r, g, b)),
sin(self.bar_index / 5) * magnitude + sma[0] if self.bar_index % 3 == 0 else nan,
plot.Marker(self.close[0] + magnitude / 2.0 if self.bar_index % 20 == 0 else nan, text='WOW' + str(self.bar_index % 3 + 1)),
)
```
## Plot display options - hide the unnecessary parts from the chart
When the indicator draws many different lines, the chart may become "too noisy". It often happens that you don't need to display all the chart elements on the chart, for example, you need to leave only the line without its numeric value, or vice versa, leave only the number but hide the line. And then the plot display options come to the rescue.
You can configure this via the UI in the indicator settings:

Or you can configure it in the indicator code:
```py Plot display options - hide the unnecessary parts from the chart
# Copyright (c) 2024 @TakeProfit. All rights reserved.
# This work is licensed under the MIT License.
# For a copy, see .
# indie:lang_version = 5
from indie import indicator, plot, color
@indicator('My Indie 1', overlay_main_pane=True)
@plot.line(color=color.BLUE, display_options=plot.LineDisplayOptions(
pane=False,
status_line=False,
price_label=True,
))
@plot.marker(color=color.GREEN, display_options=plot.MarkerDisplayOptions(
pane=True,
status_line=False,
price_label=False,
))
@plot.steps(color=color.RED, display_options=plot.StepsDisplayOptions(
pane=False,
status_line=True,
price_label=False,
))
def Main(self):
return self.close[0], self.close[0] + 300.0, self.close[0] + 500.0
```
There are three parameters here:
* pane - to display an element (line, markers, etc.) on a chart pane;
* status\_line - to display a numeric value next to the name and settings of the indicator;
* price\_label - to display a numeric value on the ordinate axis of the graph.
With plot display options, you have more options to customize the appearance of the indicator.
# null
Source: https://takeprofit.com/docs/indie/Data-types-in-Indie
This section is an overview of core data types of the Indie language.
## Basic data types
They are:
* `float` — type of double precision (64-bit) floating point numbers
* `int` — integer numbers
* `bool` — boolean values `True` or `False`
* `str` — string data type
## `indie.Optional[T]` class
In Indie (unlike in Python) it is not allowed to assign `None` value to a variable of any arbitrary type (e.g. basic
data types). But it is allowed to do so with the help of `indie.Optional[T]` class.
`indie.Optional[T]` is similar to Python's `typing.Optional[T]` with a few significant differences:
* `None` can be assigned to values which have `indie.Optional[T]` type only. `None` cannot be assigned to values of some
`T` type which is not an optional type
* to write some value to an optional variable just simple assignment operator should be used
* to access `T` value which is stored in `indie.Optional[T]` it is required to explicitly call `value()` or `value_or()` method
* if `value()` method is called on an optional variable which is `None` it raises runtime error
* to test if optional variable has some value stored inside `is None` and `is not None` constructs should be used
* if variable was declared as `indie.Optional[T]` then `T` cannot be changed for that variable to some other type `U`
For example this will not work in Indie:
```py
a = None # compilation error
# ...
a = 42
```
Indie compiler cannot infer `T` type for `a` in this example. Yes, it may guess that `a` is of `indie.Optional` type,
but it is unclear how to guess that `T` will be an `int` for it.
This will not work too:
```py
a: int = None # compilation error
# ...
a = 42
```
In this case, well, it is explicitly declared that `a` is not an optional type, so `None` cannot be assigned to it.
That is why type of `a` must be declared explicitly as an optional type:
```py
a: indie.Optional[int] = None
a = 42
# ...
a = 'foobar' # compilation error
```
Once variable `a` was declared as optional of `int` value, it cannot at some point start to store `str` values.
By the way if you do not assign any value to an optional variable it will be `None` too:
```py
a: indie.Optional[int] = None
b: indie.Optional[int]
```
Both `a ` and `b` in this example are `None`.
To check if optional variable `a` is `None` or not we use:
```py
if a is None:
# ...
if a is not None:
# ...
```
To access value stored in optional variable `a`, the `value()` method should be explicitly called:
```py
if a is not None:
b = a.value()
```
If an optional variable has no value stored inside then `value()` method call raises a runtime error. For example:
```py
s: indie.Optional[str]
t = s.value() # runtime error, because `s is None == True`
```
But this works fine:
```py
s: indie.Optional[str] = 'foobar'
t = s.value()
```
because in this case string `'foobar'` is stored in optional variable `s`.
## Built-in container types
At the moment (Indie v4) only `list[T]` is implemented in the Indie language. There are partial support of a `tuple[T]`.
It is planned to add support for `dict[K, V]` and `set[T]` in the near future.
## Series data types
* `indie.Series[T]` and an alias `indie.SeriesF` for `indie.Series[float]`
* `indie.MutSeries[T]` and an alias `indie.MutSeriesF` for `indie.MutSeries[float]`
`Series[T]` is a read-only container which stores series of `T` values. `MutSeries[T]` extends `Series[T]` with only
`__setitem__` method, which allows writing to the last element of the container (which syntactically looks like
`some_mut_series[0] = some_value`).
Type `T` can be (almost) any type in Indie, not just `float`, but also `int`, `bool`, `str`, etc.
## Context data types
There are three context classes:
* `indie.Context` is a base class that represents a context of a chart instrument
* `indie.MainContext` is a class that represents main context, extends `indie.Context`
* `indie.SecContext` is a class that represents secondary context, extends `indie.Context`
## Algorithm base class
There is a `indie.Algorithm` base class. All algorithms from `indie.algorithms` package are inherited from it.
# Fills, levels and bands
Source: https://takeprofit.com/docs/indie/Fills-levels-and-bands
## Fills
Area in between any two plots can be filled with a color (often semi-transparent). To use this feature there is a
[`@plot.fill`](/indie/Library-reference/package-indie-plot#decor_fill) decorator and a [`plot.Fill`](/indie/Library-reference/package-indie-plot#class_Fill) class.
In the first place the `@plot.fill` decorator declares which two plots should be used for filling. Optionally
it may have a color argument, which should be used if a single-colored fill is desired.
### Single-colored fill
The simplest possible usecase fills the space between two plot lines:
```py
# indie:lang_version = 5
from indie import indicator, color, plot
@indicator('Example 1', overlay_main_pane=True)
@plot.line('p1')
@plot.line('p2')
@plot.fill('p1', 'p2', color=color.BLUE(0.2))
def Main(self):
a = self.high
b = self.low
return a[0], b[0], plot.Fill()
```

Please note, that both `@plot.fill` decorator and `plot.Fill` object always must be used together. Even in simple cases of a
single-colored fills where `plot.Fill` object is constructed with all default values (i.e. with no arguments `plot.Fill()`).
### Multicolored fill
If a multicolored fill is needed, then the color value should be calculated in the `Main` function code and passed as
argument to a `plot.Fill` object returned by the `Main` function.
```py
# indie:lang_version = 5
from indie import indicator, color, plot
@indicator('Example 2', overlay_main_pane=True)
@plot.line('p1')
@plot.line('p2')
@plot.fill('p1', 'p2')
def Main(self):
c = color.GREEN(0.5) if self.close[0] > self.open[0] else color.RED(0.5)
return self.high[0], self.low[0], plot.Fill(color=c) # NOTE: This color will override color in @plot.fill decorator if any
```

### Multicolored fill with an offset
`plot.Fill()` has an optional parameter `offset: int`. It may be used to shift the coloring to the left (if `offset` is
negative) or to the right (if `offset` is positive):
```py
# indie:lang_version = 5
from indie import indicator, color, plot, param
@indicator('Example 3', overlay_main_pane=True)
@plot.line('p1')
@plot.line('p2')
@plot.fill('p1', 'p2')
@param.int('fill_offset', default=2)
def Main(self, fill_offset):
c = color.GREEN(0.5) if self.close[0] > self.open[0] else color.RED(0.5)
return self.high[0], self.low[0], plot.Fill(color=c, offset=fill_offset)
```
Please note, that a non-zero fill `offset` has effect only to multi-colored fills and has none to single-colored ones.
## Levels
[`@level()`](/indie/Library-reference/package-indie#decor_level) decorator creates a level (horizontal line).
```txt
@level(
value: float,
title: indie.Optional[str] = None,
line_color: indie.Color = indie.color.GRAY(0.5),
line_style: int = indie.line_style.DASHED,
line_width: int = 1
) -> NoneType
```
Parameters:
* `value` — Value of the level on a vertical scale of an indicator.
* `title` — Human readable title which is visible in the indicator's Settings panel.
* `line_color` — Color of the line.
* `line_style` — Style of the line. It is represented as enum value of type `line_style`.
* `line_width` — Width of the line.
Example:
```py
# indie:lang_version = 5
from indie import indicator, level, color
@indicator('Level example')
@level(150, line_color=color.RED, line_width=4)
def Main(self):
return self.close[0]
```

## Bands
[`@band()`](/indie/Library-reference/package-indie#decor_band) decorator creates a band (two horizontal lines usually with a semi-transparent fill in between them).
```txt
@band(
value1: float,
value2: float,
title: indie.Optional[str] = None,
fill_color: indie.Color = indie.color.GREEN(0.05),
line_color: indie.Color = indie.color.GRAY(0.5),
line_style: int = indie.line_style.DASHED,
line_width: int = 1
) -> NoneType
```
Parameters:
* `value1` — Value of the first horizontal line of a band on a vertical scale of an indicator.
* `value2` — Value of the second horizontal line of a band on a vertical scale of an indicator.
* `title` — Human readable title which is visible in the indicator's Settings panel.
* `fill_color` — Color of the background.
* `line_color` — Color of the line.
* `line_style` — Style of the line. It is represented as enum value of type `line_style`.
* `line_width` — Width of the line.
Example:
```py
# indie:lang_version = 5
from indie import indicator, band, color
@indicator('Band example')
@band(145, 155, line_color=color.RED, line_width=4)
def Main(self):
return self.close[0]
```

# null
Source: https://takeprofit.com/docs/indie/How-Indies-syntactic-sugar-works
Indie programming language has several [*syntactic sugar*](https://en.wikipedia.org/wiki/Syntactic_sugar) constructs
which simplify a lot writing code of technical analysis indicators for TakeProfit platform.
## `Main` entry point
Every indicator in Indie has a `Main` entry point. It could be written in one of two forms: as a `Main` *function
definition* which is a form of syntactic sugar or as a `Main` *class definition* (which is not).
### `Main` function definition
Here is an example of minimal indicator written in a form of a `Main` as a function definition:
```py
# indie:lang_version = 5
from indie import indicator
@indicator('Example')
def Main(self):
return self.close[0]
```
This form is very compact therefore it is recommended for simple indicators.
When Indie compiler sees a combination of a function definition with name `Main` decorated with `@indicator` it transforms it into a `Main` class definition (i.e. to the second form) according to a few simple rules:
* function definition is replaced with a `Main` class definition which is inherited from `indie.MainContext` base class;
* the body of `Main` function becomes `Main.calc()` method;
* `Main` class may optionally have `__init__` constructor (only if it is needed).
This transformation is automatic and hidden from user, that is why the first form of `Main` entry point is considered to
be a syntactic sugar. In some cases when indicator needs greater control over what is happening in the code the second form of writing the indicator's `Main` entry point with classes syntax can be used explicitly.
### `Main` written as a class definition
Indicator could be written using the second form of a `Main` entry point which uses class definition syntax:
```py
# indie:lang_version = 5
from indie import indicator, MainContext
@indicator('Example')
class Main(MainContext):
def __init__(self):
pass
def calc(self):
return self.close[0]
```
Writing indicator in the second form using class syntax is less compact but it has it's advantages, for example user is
able to declare `__init__` constructor method and place some one-time initialization code there. Therefore for
indicators with complex logic you probably would like to use the second form. Constructor `__init__` is optional though.
## Functions decorated with `@algorithm`
Functions decorated with `@algorithm` are automatically transformed by Indie compiler into classes inherited from
`indie.Algorithm`. For example:
```py
# indie:lang_version = 5
from indie import algorithm, SeriesF
from indie.algorithms import Ema
@algorithm
def DoubleEma(self, src: SeriesF, length: int) -> SeriesF:
ema1 = Ema.new(src, length)
ema2 = Ema.new(ema1, length)
return ema2
```
Will be transformed into a class form:
```py
# indie:lang_version = 5
from indie import Algorithm, SeriesF, Context
from indie.algorithms import Ema
class DoubleEma(Algorithm):
def __init__(self, ctx: Context):
super().__init__(ctx)
def calc(self, src: SeriesF, length: int) -> SeriesF:
ema1 = Ema.new(src, length)
ema2 = Ema.new(ema1, length)
return ema2
```
Users are able to choose which form they want to use in their indicators' code. Of course, as with `Main` entry point,
the decorator-based form is preferred in most cases. Class form should be used only in more complex cases, where a
more fine-grained control is needed.
Decorator `@algorithm` is also a syntactic sugar in Indie language. Here are the simple rules that Indie compiler uses
to process it:
* function definition decorated with `@algorithm` is replaced with a class with the same name inherited from
`indie.Algorithm` base class;
* original function becomes a `calc` method of this class, function body does not change;
* `__init__` constructor is added to the generated class which accepts `ctx: indie.Context` parameter and forwards it to
the parent constructor;
NOTE: to get OHLCV values of the current instrument from the algorithm methods there is a `self.ctx` property of
`indie.Context` type. For example to get access to close prices use `self.ctx.close` expression.
The `DoubleEma` algorithm from the example above could be created and used in two ways:
* Using `DoubleEma.new()` static method (`new` is a method of parent class `indie.Algorithm`, well... not exactly but
kind of). This is a syntactic sugar that allows to use any algorithm right in the place where it is needed in the
indicator (e.g. in `def Main` function, or in the function body of some other algorithm).
* Using `DoubleEma()` constructor in `__init__` method of a corresponding `MainContext`, `SecContext` or other
`Algorithm`. Then, in the `calc` method of a corresponding `MainContext`, `SecContext` or other
`Algorithm` you should explicitly call the `DoubleEma`'s `calc()` method.
## `Algorithm.new()` method
Method `Algorithm.new()` is used to create and use algorithm objects in Indie. It looks like a static method, but
it behaves very differently because it is also a syntactic sugar of the language. When Indie compiler sees a call, e.g.
`res = Ema.new(src, length)`, it uses the following rules to transform such a piece of code:
* a class field is created in corresponding `__init__` constructor of the enclosing `MainContext`, `SecContext` or other
`Algorithm`. In our example it would be: `self._ema1 = Ema(ctx)` (in case `self` is a `Context`) or
`self._ema1 = Ema(self.ctx)` (in case `self` is an `Algorithm`).
* the call of `Ema.new` is replaced with `self._ema1.calc` call. In our example it would be
`res = self._ema1.calc(src, length)`.
Here is a full example of such transformation:
```py
# indie:lang_version = 5
from indie import Algorithm, SeriesF, Context
from indie.algorithms import Ema
class DoubleEma(Algorithm):
def __init__(self, ctx: Context):
super().__init__(ctx)
def calc(self, src: SeriesF, length: int) -> SeriesF:
ema1 = Ema.new(src, length)
ema2 = Ema.new(ema1, length)
return ema2
```
Will be transformed into:
```py
# indie:lang_version = 5
from indie import Algorithm, SeriesF, Context
from indie.algorithms import Ema
class DoubleEma(Algorithm):
def __init__(self, ctx: Context):
super().__init__(ctx)
self._ema1 = Ema(self.ctx)
self._ema2 = Ema(self.ctx)
def calc(self, src: SeriesF, length: int) -> SeriesF:
ema1 = self._ema1.calc(src, length)
ema2 = self._ema2.calc(ema1, length)
return ema2
```
Of course, syntactic sugar of `Algorithm.new()` works only inside methods of descendants of `MainContext`, `SecContext`
or other `Algorithm` classes (except the `__init__` constructors). You cannot use this functionality in plain
Python-like functions.
Syntactic sugar of `Algorithm.new()` method can be used with any Indie algorithm regardless of the form in which the
algorithm was written (the decorator-based form or the class-based form).
## `MutSeries[T].new()` method
Method `MutSeries[T].new()` (or `MutSeriesF.new()` where `MutSeriesF` is an alias for `MutSeries[float]`) is used to create and use mutable series objects in Indie. It looks like a static method, but
it behaves very differently because it is also a syntactic sugar of the language. When Indie compiler sees a call, e.g.
`s = MutSeriesF.new((a + b) / 2)`, it uses the following rules to transform such a piece of code:
* a class field is created in corresponding `__init__` constructor of the enclosing `MainContext`, `SecContext` or
`Algorithm`. In our example it would be: `self._ms1 = self.new_mut_series_f()` (in case `self` is a `Context`) or `self.ctx.new_mut_series_f()` (in case `self` is an `Algorithm`).
* the call of `MutSeriesF.new` is replaced with `self._ms1.calc` call. In our example it would be
`s = self._ms1.calc((a + b) / 2)`. Method `MutSeriesF.calc` writes given expression `(a + b) / 2` into the last
element of the mutable series object and returns a reference to the mutable series itself.
For example:
```py
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def Hl2(self) -> SeriesF:
h = self.ctx.high
l = self.ctx.low
return MutSeriesF.new((h[0] + l[0]) / 2)
```
transforms into:
```py
# indie:lang_version = 5
from indie import Algorithm, SeriesF, MutSeriesF, Context
class Hl2(Algorithm):
def __init__(self, ctx: Context):
super().__init__(ctx)
self._ms1 = self.ctx.new_mut_series_f()
def calc(self) -> SeriesF:
h = self.ctx.high
l = self.ctx.low
return self._ms1.calc((h[0] + l[0]) / 2)
```
In this example two transformations took place at once: syntactic sugar of `@algorithm` and `MutSeriesF.new()` call.
## Functions decorated with `@sec_context`
Functions decorated with `@sec_context` are used to create secondary entry-points (besides `Main`) which are needed when
indicator requests data of additional instruments. And decorator `@sec_context` is syntactic sugar, because every time
Indie compiler sees a function definition decorated with `@sec_context` it transforms it into a class, inherited from
`indie.SecContext` according to a few simple rules:
* function definition decorated with `@sec_context` is replaced with a class with the same name inherited from
`indie.SecContext` base class;
* the body of the function becomes a `calc()` method of the generated class;
* generated class may optionally have `__init__` constructor (only if it is needed).
Let us see how it works with an example, this piece of code:
```py
# indie:lang_version = 5
from indie import sec_context
@sec_context
def SecHighLow(self):
return self.high[0], self.low[0]
```
transforms into this:
```py
# indie:lang_version = 5
from indie import SecContext
class SecHighLow(SecContext):
def calc(self):
return self.high[0], self.low[0]
```
The code that actually uses the `SecHighLow` looks like this:
```py
# indie:lang_version = 5
from indie import indicator, TimeFrame
# >>> definition of SecHighLow is here <<<
@indicator('MyIndie')
class Main(MainContext):
def __init__(self):
self._h, self._l = self.calc_on(SecHighLow, time_frame=TimeFrame.from_str('1D'))
def calc(self):
return self._h[0], self._l[0]
```
NOTE that in the Indie (since version 4) it is allowed to call `Context.calc_on` only from `__init__` constructors.
# Indicator Code Structure
Source: https://takeprofit.com/docs/indie/Indicator-code-structure
The general code structure of an indicator 'module' looks like this:
```txt
COMMENT_DIRECTIVES
IMPORTS
HELPER_FUNCTION_DEFINITIONS (optional)
DECORATED_HELPER_FUNCTION_DEFINITIONS (optional)
CLASS_DEFINITIONS (optional)
MAIN_FUNCTION_OR_CLASS_DEFINITION
```
`HELPER_FUNCTION_DEFINITIONS`, `DECORATED_HELPER_FUNCTION_DEFINITIONS`, `CLASS_DEFINITIONS` and `MAIN_FUNCTION_OR_CLASS_DEFINITION` can go in any order.
Syntactically, Indie code is a Python code. But, there are some
[differences](/indie/Language-differences-with-Python) that you may want to be aware about.
## Comment directives
Comment directives are special comments that have some effect on how Indie's compiler and/or runtime works.
At the moment there is only one comment directive which is:
```py
# indie:lang_version = 5
```
and it declares the language version of the source code of the indicator.
## Imports
The IMPORTS section consists of several `import` statements. Every `import` statement tells Indie runtime to import
(or connect) one or more symbols from [libraries](/indie/Library-reference/package-indie). After that these symbols may
be used in the indicator code.
```py
from indie import indicator # This line imports the `indicator`
# decorator from `indie` library package
@indicator('Example') # Here we use the imported `indicator` decorator
def Main(self):
# ...
```
Like in Python, there are several different forms of imports:
```py
import indie.algorithms # Then you can use any symbols from this package
# with their full name, e.g. `indie.algorithms.Sma`
import indie.algorithms as alg # Then you can use any symbols from this package
# with a short package alias, e.g. `alg.Sma`
from indie.algorithms import Sma # Then you can use only `Sma` symbol from
# this package (without the package prefix)
from indie.algorithms import Sma as my_sma # Then you can use the symbol
# with an alias `my_sma`
```
Also in every `from` form you are allowed to use lists of symbols, for example:
```py
from indie.algorithms import Sma, Wma, Ema
from indie.algorithms import Sma as s, Wma as w, Ema as e # You can do this, but this is not a
# good coding style! Because this makes
# your code harder to read and understand
```
One note about the aliases. Do not use them if you do not really need them. And you most certainly will need them in two
cases:
* You have a name clash of two symbols from different libraries. Add an alias to one or both of the symbols to
resolve the clash. For example:
```py
from some.library import foobar_func
from another.library import foobar_func
```
Obviously, when you try to call the imported function `foobar_func()` afterwards, it is unclear which one of the two
imported functions should be called. Such code cannot be run and produces an error.
Same example with a name clash resolved:
```py
from some.library import foobar_func
from another.library import foobar_func as another_foobar_func
# Now you may call both `foobar_func()` and `another_foobar_func()` without any ambiguity
```
* You import a symbol with a long name, and it is very uncomfortable to use that long name in the code:
```py
from some.library import some_useful_function_with_a_very_long_name
# Call the function later as `some_useful_function_with_a_very_long_name()`
```
Instead, it is better to use an alias:
```py
from some.library import some_useful_function_with_a_very_long_name as useful_func
# Call the function later as `useful_func()`
```
## Helper function definitions
Indicator algorithms could be quite complex, so it is a good coding style to extract blocks of code into
helper functions with some meaningful names. The minimal function that accepts no arguments, does nothing
(Python keyword `pass` is about that) and returns nothing (`None`) looks like this:
```py
def minimal_helper_func() -> None:
pass
```
Obviously there will be not much help of such a helper function like `minimal_helper_func`, it's just an example.
Here is a more realistic example of a function that calculates a maximum of given two integers:
```py
def max(a: int, b: int) -> int:
if a > b:
return a
else:
return b
```
At the moment, it is mandatory to declare type hints for every argument as well as for the return value of all the
functions (except for the `Main` function and `@sec_context`-decorated functions). Read more about typing in the
[Data types in Indie](/indie/Data-types-in-Indie) chapter.
## Decorated helper function definitions
There are two decorators that can be applied to helper functions: `@algorithm` and `@sec_context`. Both of them are
syntactic sugar decorators which help a lot in making indicator code compact and readable.
The `@algorithm` decorator is a syntactic sugar for making your own
[series processing algorithm](/indie/Algorithms-for-series-processing) like `indie.algorithms.Sma`.
```py
@algorithm
def SomeFunc(self) -> SeriesF:
# Some code...
```
The `@sec_context` decorator is a syntactic sugar for making an extra entry point function (like a secondary `Main`) for
additional instrument that indicator may request. This function should be used in combination with a `Context.calc_on`
function. Read more about it in [Request additional instruments](/indie/Request-additional-instruments).
```py
@sec_context
def SomeSecContext(self):
# Some code, that processes the BINANCEUS:BTC/USD candles data...
@indicator('Example')
class Main(MainContext):
def __init__(self):
self._sec_context_res = self.calc_on(SomeSecContext, exchange='BINANCEUS', ticker='BTC/USD')
def calc(self):
# Some code that uses self._sec_context_res
```
## Class definitions
From Indie v4 the language partially supports [OOP](https://en.wikipedia.org/wiki/Object-oriented_programming) and this
support is going to be expanded. At the moment this means that Indie has `class` keyword that lets to declare classes,
just like in Python.
For example the `Main` entry point could be declared not as a function, but as a class, like this:
```py
# indie:lang_version = 5
from indie import indicator, MainContext
@indicator('Example')
class Main(MainContext):
def calc(self):
return self.close[0]
```
Constructor (the `__init__` method) could be optionally added too. It is very useful because it is a good place for some
initialization code that must be executed only once. For example:
```py
# indie:lang_version = 5
from indie import indicator, MainContext, IndieError
@indicator('Example')
class Main(MainContext):
def __init__(self):
# This code is executed only once at the creation
# of the indicator before calculations on candle data
c: str
if 'EUR' in self.info.ticker:
c = 'EUR'
elif 'JPY' in self.info.ticker:
c = 'JPY'
elif 'USD' in self.info.ticker:
c = 'USD'
else:
raise IndieError('This indie cannot be added on ' + self.info.ticker + ' chart')
self._currency = c
def calc(self):
# Calculations on candle data are here
# TODO: Use `self._currency` somehow here...
return self.close[0]
```
Secondary contexts can be declared as classes (instead of using `@sec_context` decorator on a func) in a similar way,
for example:
```py
# indie:lang_version = 5
from indie import SecContext
class SecHighLow(SecContext):
def calc(self):
return self.high[0], self.low[0]
```
Finally, algorithms (instead of using `@algorithm` decorator on a func) can be declared as classes too, for example:
```py
# indie:lang_version = 5
from indie import Algorithm, Context, SeriesF, MutSeriesF
class MyAlgorithm(Algorithm):
def __init__(self, ctx: Context):
super().__init__(ctx)
def calc(self, src1: SeriesF, src2: SeriesF) -> SeriesF:
return MutSeriesF.new(src1[0] + src2[0])
```
## Main function or class definition
```py
@indicator('Example 1')
def Main(self):
# Some code here...
```
The `Main` entry point of the whole indicator is mandatory. It is called every time the indicator receives a candle data
update and it should return an indicator result for that piece of data. It must have at least one parameter `self` which
is a reference to object of `Main` class (inherited from [`MainContext`](/indie/Library-reference/package-indie#class_MainContext) type).
Function or class `Main` must also be decorated with a [`@indicator`](/indie/Library-reference/package-indie#decor_indicator) decorator. But
also other decorators could be added here, for example:
* Decorator [`@plot.line`](/indie/Library-reference/package-indie-plot#decor_line)
* Decorators [`@plot.fill`, `@level` and `@band`](/indie/Fills-levels-and-bands)
* Decorators [`@param.*`](/indie/Input-parameters) for declaring input parameters of an indicator
# null
Source: https://takeprofit.com/docs/indie/Input-parameters
*Input parameters* provide a convenient way to change indicator's algorithm parameters without the need of changing it's
source code. For example, here is a simple indicator that calculates SMA with two parameters `src` and `length`:
```py
# indie:lang_version = 5
from indie import indicator, param, source
from indie.algorithms import Sma
@indicator('Example')
@param.source('src', default=source.CLOSE, title='Source')
@param.int('length', default=12, min=1, title='Length')
def Main(self, src, length):
sma = Sma.new(src, length)
return sma[0]
```
After this indicator will be added to a chart, the values for the `length` and `source` parameters can be easily changed
in indicator's *Settings* dialog:

## How to add a parameter to an indicator
There are a few simple steps for adding an input parameter to indicator:
* Add one of the `@param.*` decorators (e.g. `@param.int`) to the `Main` entry point of the indicator.
* Pass values for the two required arguments to the decorator:
* `id` — which is a string unique identifier of the parameter (the very first argument of any `@param.*` decorator),
* `default` — which is a default value of the parameter.
* Pass values to optional arguments of the decorator if needed (this depends on the decorator type, they
could differ). In the example above there are optional arguments `title` and `min`.
* Add a parameter to `Main` function (after the `self` parameter) with the name which is equal to the `id` of the
parameter.
## Available parameter types
Indie supports several types of input parameters, they are:
* `int`, created with decorator [`@param.int`](/indie/Library-reference/package-indie#decor_param_int)
* `bool`, created with decorator [`@param.bool`](/indie/Library-reference/package-indie#decor_param_bool)
* `float`, created with decorator [`@param.float`](/indie/Library-reference/package-indie#decor_param_float)
* `str`, created with decorator [`@param.string`](/indie/Library-reference/package-indie#decor_param_string)
* source of type [`SeriesF`](/indie/Library-reference/package-indie#class_SeriesF), created with decorator [`@param.source`](/indie/Library-reference/package-indie#decor_param_source)
* time frame of type [`TimeFrame`](/indie/Library-reference/package-indie#class_TimeFrame), created with decorator [`@param.time_frame`](/indie/Library-reference/package-indie#decor_param_time_frame)
# null
Source: https://takeprofit.com/docs/indie/Language-differences-with-Python
## Syntactic constructs of Indie
Indie is a subset of Python syntax constructs, namely:
* supported features in Indie:
* function definitions (at top level only)
* basic control statements: `if`, `for`, `while`
* variable declarations and standard arithmetics
* basic data types are: `int`, `float`, `bool`, `str`
* decorators from the Indie's standard library (like `@indicator`, `@algorithm` and others)
* `raise`-ing exceptions
* (NOTE: this is a work in progress) container data types: `list`, `tuple`. Indie requires explicit typing of
the contained items
* some limited (yet) support of classes and OOP
* ...
* not (yet) supported in Indie v3:
* nested function definitions
* lambdas
* generator expressions
* `try`..`except` construct
* `with`..`as` construct
* containers `list` and `tuple` are implemented partially. The other ones e.g. `dict` and `set` are not yet
implemented
* f-strings
* functions as first class objects (ability to pass function as an argument to another function call). There is an
exception here — function `Context.calc_on` actually accepts a function as one of it's arguments... But you cannot
write your own custom functions that do the same thing
* ...
## Explicit typing
Indie requires to explicitly declare types of all variables, function parameters and function return values, except for
the cases when Indie compiler is able to infer types from the context around. Luckily, in most cases it is able to do
so. For example:
```py
a = 25 # No need to declare type of `a`, because it is initialized with an int literal. So type of `a` is int
b = a + 5 # No need to declare type of `b`, it's type is inferred as int too
```
Another example:
```py
hist_color: Optional[Color] = None # We have to declare type of `hist_color` here explicitly
# otherwise `hist_color = None` tells compiler nothing about
# the type of `hist_color` variable
if hist[1] < hist[0]:
hist_color = color.NAVY
else:
hist_color = color.BLUE
```
Example of a function signature with typing:
```py
def Sma(self, price: Series[float], length: int) -> Series[float]:
# ...
```
## Scopes of variables
In Python, variables declared in `if`-statements, `for`-loop blocks, and `while`-loop blocks are not local variables,
and stay in scope outside of the block. Indie, on the other hand, has 'block-level' scoping which is very similar to
such languages like C/C++, Java, Go. For example, in Python it's normal to write (but will fail to compile in Indie):
```py
def some_func(cond: bool) -> int:
if cond:
res = 42
else:
res = 0
return res
```
In Indie, variable `res` will not exist after the `if`..`else` statements. Moreover `res` of the `if` block is a different
variable than the `res` from the `else` block. So this example in Indie should be rewritten into:
```py
def some_func(cond: bool) -> int:
res: int
if cond:
res = 42
else:
res = 0
return res
```
## Assignments of `None` values
In Indie it is not allowed to assign `None` value to a variable of any arbitrary type (e.g. basic data types). But it is
allowed to do so with the help of `indie.Optional[T]` class. Read more about this
[here](/indie/Data-types-in-Indie#indie-optionalt-class).
## Syntactic sugar constructs
There are a few language constructs in Indie, which behave weird from the point of view of a standard Python. They are
nothing more but a syntactic sugar for somewhat complicated things thus they make writing technical analysis indicators
simpler. They are:
* `Main` function which transforms into a `Main` class inherited from `indie.MainContext`.
* Functions decorated with `@algorithm` (more info [here](/indie/Algorithms-for-series-processing)) which transform into classes inherited from `indie.Algorithm`.
* `Algorithm.new()` static method (e.g. `indie.algorithms.Sma.new()`).
* `MutSeries[T].new()` static method.
* Functions decorated with `@sec_context` decorator which transform into classes (similar to `Main`) inherited from `indie.SecContext`.
More information about this in [How Indie's syntactic sugar works](/indie/How-Indies-syntactic-sugar-works) section
## Libraries to import from
You may think, 'Indie is a Python-like language... so... I will import numpy, pandas, yfinance, matplotlib,
talib and a lot more cool and very helpful stuff into my TakeProfit indicators right now and have some fun!'
but... unfortunately you cannot do this. Well, at least right now.
There are number of reasons why. Here are some of them:
* Those libraries are not compatible with Indie's runtime design and internal data types.
* Many of those libraries run on CPython, we in TakeProfit cannot use it effectively as our backend runtime.
We are looking forward to WebAssembly/machine code to reach higher performance. We simply cannot run these
libraries' code on those.
* There are a lot of stuff in those libraries which is not allowed to run on our servers due to our
'sandbox'-related policies.
* We in TakeProfit are too busy to work on integration of our runtime engine with those libraries at the moment,
because there are a lot of stuff yet to do to make Indie a great tool for technical analysis.
So, in other words, the fact that Indie is a Python-like language gives it an additional point of growth here. But
this is a very complicated task, and it is hard to give any promises/estimates right now about it.
Now, what you can import into Indie right now, is:
* Core stuff from the [standard library](/indie/Library-reference/package-indie) package `indie`,
like `indicator`, `algorithm`, `sec_context`, `Series[T]`, etc.
* Classic tech analysis algorithms from the [standard library](/indie/Library-reference/package-indie-algorithms) package `indie.algorithms`,
like `Sma`, `Ema`, `Highest`, `Lowest`, etc.
* Some bits and pieces of the Python standard core libraries:
* `math.pow`
* `math.sqrt`
* `math.nan`
* `math.isnan`
* `statistics.mean`
* `statistics.fmean`
* `statistics.median`
The list of items to be imported will definitely be expanded... Please, be patient.
## Python built-ins
Standard Python has many built-ins. Indie has only these:
`None`, `NoneType`, `False`, `True`, `abs()`, `bool()`, `dict()`, `float()`, `int()`, `len()`, `list()`,
`min()`, `max()`, `range()`, `round()`, `str()`, `sum()`, `tuple()`.
## Indie code runs in a sandbox
We run Indie code on our servers, that is why for the obvious reasons Indie's runtime is sandboxed.
It means that it is very restricted in terms of what is allowed to do with the host system where code is being executed.
For example file and socket I/O is not allowed, execution time and memory are limited too.
# Overview
Source: https://takeprofit.com/docs/indie/Library-reference-overview
Indie includes several core packages that provide functions for data processing, scheduling, and plotting.
Most of Indie's functionality is located in the `indie` and `indie.*` packages, while others, like `math`,
contain features adapted from Python's standard libraries.
The main package of Indie, containing essential components.
A collection of built-in algorithms for technical analysis.
Tools for plotting series-based data on charts.
Built-in colors and the `rgba` function.
Utility functions for simple calculations.
Classes for defining and handling trading schedules.
Tools for working with dates and times.
Statistical functions and calculations.
Standard mathematical functions.
Built-in types, constants, and functions of Indie.
# Builtins
Source: https://takeprofit.com/docs/indie/Library-reference/builtins
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Built-in symbols of Indie language.
***
## Variables
Built-in Indie object (similar to Python's).
Built-in Indie object (similar to Python's).
Built-in Indie object (similar to Python's).
***
## Functions
### `abs()`
*function*
Returns the absolute value of a number. It is a built-in Indie function (similar to Python's).
Number on which the function will be calculated.
Returns the absolute value of a number. It is a built-in Indie function (similar to Python's).
Number on which the function will be calculated.
***
### `len()`
*function*
Returns the length (the number of items) of an object. It is a built-in Indie function (similar to Python's).
Value on which the function will be calculated.
***
### `max()`
*function*
Returns the largest of two or more arguments. It is a built-in Indie function (similar to Python's).
First number to calculate the function.
Second number to calculate the function.
Returns the largest of two or more arguments. It is a built-in Indie function (similar to Python's).
First number to calculate the function.
Second number to calculate the function.
Third number to calculate the function.
Returns the largest of two or more arguments. It is a built-in Indie function (similar to Python's).
First number to calculate the function.
Second number to calculate the function.
Returns the largest of two or more arguments. It is a built-in Indie function (similar to Python's).
First number to calculate the function.
Second number to calculate the function.
Third number to calculate the function.
Returns the largest of two or more arguments. It is a built-in Indie function (similar to Python's).
List on which the function will be calculated.
Returns the largest of two or more arguments. It is a built-in Indie function (similar to Python's).
List on which the function will be calculated.
***
### `min()`
*function*
Returns the smallest of two or more arguments. It is a built-in Indie function (similar to Python's).
First number to calculate the function.
Second number to calculate the function.
Returns the smallest of two or more arguments. It is a built-in Indie function (similar to Python's).
First number to calculate the function.
Second number to calculate the function.
Third number to calculate the function.
Returns the smallest of two or more arguments. It is a built-in Indie function (similar to Python's).
First number to calculate the function.
Second number to calculate the function.
Returns the smallest of two or more arguments. It is a built-in Indie function (similar to Python's).
First number to calculate the function.
Second number to calculate the function.
Third number to calculate the function.
***
### `range()`
*function*
Creates a list containing the specified range of numbers that is used in `for` loops. It is a built-in Indie function (similar to Python's).
Last value of the range (exclusive).
```py Example
x = 0
for i in range(10):
x += i
```
The behavior of this function is similar to Python's 2 built-in function `range` and is ineffective. This will be fixed in future versions of Indie.
Creates a list containing the specified range of numbers that is used in `for` loops. It is a built-in Indie function (similar to Python's).
First value of the range.
Last value of the range (exclusive).
Step value of the range.
```py Example
x = 0
for i in range(10):
x += i
```
The behavior of this function is similar to Python's 2 built-in function `range` and is ineffective. This will be fixed in future versions of Indie.
***
### `round()`
*function*
Returns number rounded to ndigits precision after the decimal point. If ndigits is omitted or is None, it returns the nearest integer to its input. It is a built-in Indie function (similar to Python's).
Number on which the function will be calculated.
Returns number rounded to ndigits precision after the decimal point. If ndigits is omitted or is None, it returns the nearest integer to its input. It is a built-in Indie function (similar to Python's).
Number on which the function will be calculated.
Rounding precision.
***
### `sum()`
*function*
Sums start and the items of a list from left to right and returns the total. It is a built-in Indie function (similar to Python's).
List on which the function will be calculated.
Initial value to calculate sum of the list.
Sums start and the items of a list from left to right and returns the total. It is a built-in Indie function (similar to Python's).
List on which the function will be calculated.
Initial value to calculate sum of the list.
***
## Types
### `bool`
*type*
Built-in Indie type (similar to Python's).
Cast constructor for built-in Indie type. Returns a `bool` value, i.e. one of `True` or `False`. The argument is converted using the standard [Python's truth testing procedure](https://docs.python.org/3/library/stdtypes.html#truth).
Value to cast from.
Cast constructor for built-in Indie type. Returns a `bool` value, i.e. one of `True` or `False`. The argument is converted using the standard [Python's truth testing procedure](https://docs.python.org/3/library/stdtypes.html#truth).
Value to cast from.
Cast constructor for built-in Indie type. Returns a `bool` value, i.e. one of `True` or `False`. The argument is converted using the standard [Python's truth testing procedure](https://docs.python.org/3/library/stdtypes.html#truth).
Value to cast from.
Cast constructor for built-in Indie type. Returns a `bool` value, i.e. one of `True` or `False`. The argument is converted using the standard [Python's truth testing procedure](https://docs.python.org/3/library/stdtypes.html#truth).
Value to cast from.
Cast constructor for built-in Indie type. Returns a `bool` value, i.e. one of `True` or `False`. The argument is converted using the standard [Python's truth testing procedure](https://docs.python.org/3/library/stdtypes.html#truth).
Value to cast from.
***
### `dict[K, V]`
*type*
Built-in Indie type (similar to Python's).
***
### `float`
*type*
Built-in Indie type (similar to Python's).
Cast constructor for built-in Indie type. Returns a `float` number constructed from a number or a string.
Value to cast from.
Cast constructor for built-in Indie type. Returns a `float` number constructed from a number or a string.
Value to cast from.
Cast constructor for built-in Indie type. Returns a `float` number constructed from a number or a string.
Value to cast from.
Cast constructor for built-in Indie type. Returns a `float` number constructed from a number or a string.
Value to cast from.
***
### `int`
*type*
Built-in Indie type (similar to Python's).
Cast constructor for built-in Indie type. Returns an `int` object constructed from a number or a string, or return 0 if no arguments are given.
Value to cast from.
Cast constructor for built-in Indie type. Returns an `int` object constructed from a number or a string, or return 0 if no arguments are given.
Value to cast from.
Cast constructor for built-in Indie type. Returns an `int` object constructed from a number or a string, or return 0 if no arguments are given.
Value to cast from.
Cast constructor for built-in Indie type. Returns an `int` object constructed from a number or a string, or return 0 if no arguments are given.
Value to cast from.
***
### `list[T]`
*type*
Built-in Indie type (similar to Python's).
Appends given param to the end of the list.
New value that will be put to the list.
Returns list element at given index.
Index of an element in the list.
```py Example
nums = [40, 41, 42, 43]
meaning_of_life = nums[2] # returns 42 (this implicitly calls `nums.__getitem__(2)`)
```
Method `__getitem__` should never be called directly, instead `list_obj[key]` syntax should be used.
Assigns value to some\_list\[key].
Index of an element in the list.
New value that will be put to the list.
```py Example
nums = [40, 41, 42, 43]
nums[2] = 100500 # this implicitly calls `nums.__setitem__(2, 100500)`
# and now `nums` are [40, 41, 100500, 43]
```
Method `__setitem__` should never be called directly, instead `list_obj[key] = value` syntax should be used.
Delete an item from the list at the given index.
Index of an element in the list.
```py Example
nums = [40, 41, 42, 43]
del nums[2] # this implicitly calls `nums.__delitem__(2)`
```
Method `__delitem__` should never be called directly, instead `del list_obj[key]` syntax should be used.
Delete a slice from the list.
Starting index for slice. Can be omitted. See more examples below.
Ending index for slice (not included). Can be omitted. See more examples below.
Step between indexes of slice. Can be omitted. See more examples below.
```py Example
nums = [40, 41, 42, 43]
del nums[0:2] # this implicitly calls `nums.__delslice__(0, 2, 1)`
```
Method `__delslice__` should never be called directly, instead `del list_obj[slice]` syntax should be used.
Returns the length (the number of items) of a list\[T].
```py Example
nums = [40, 41, 42, 43]
len(nums) # returns 4 (this implicitly calls `nums.__len__()`)
```
Method `__len__` should never be called directly, instead `len(list_obj)` syntax should be used.
Returns `True` if the list is not empty.
Returns `True` if the list contains the given value, otherwise `False`.
Element to find in the list.
```py Example
nums = [40, 41, 42, 43]
my_bool = 41 in nums # this implicitly calls `nums.__contains__(41)`
```
Method `__contains__` should never be called directly, instead `val in lst` syntax should be used.
Removes the first item from list `s` where `s[i]` is equal to given param.
Value that will be removed from the list
```py Example
nums = [40, 41, 42, 40, 41, 42]
nums.remove(42) # now `nums` are [40, 41, 40, 41, 42]
```
Retrieves the item at given index and also removes it from the list.
Index of an element in the list.
```py Example
nums = [40, 41, 42, 43]
meaning_of_life = nums.pop(2) # now `nums` are [40, 41, 43], `meaning_of_life` is 42
```
Insert a value at the specified index.
Index of an element in the list.
New value that will be put to the list.
```py Example
nums = [40, 41, 42, 43]
nums.insert(2, 50) # now `nums` are [40, 41, 50, 42, 43]
```
Remove all items from the list.
```py Example
nums = [40, 41, 42, 43]
nums.clear() # now `nums` is []
```
Reverses the elements of the list in place.
Returns index of the first occurrence of the item in the list. If not found returns `-1`.
Element to find in the list.
Returns a slice of the list elements.
Starting index for slice. Can be omitted. See more examples below.
Ending index for slice (not included). Can be omitted. See more examples below.
Step between indexes of slice. Can be omitted. See more examples below.
```py Example
nums = [40, 41, 42, 43]
meaning_of_life = nums[1:3] # returns [41, 42] (this implicitly calls `nums.__getslice__(1, 3, 1)`)
```
Method `__getslice__` should never be called directly, instead `list_obj[slice]` syntax should be used.
Assigns given list to some\_list\[slice].
Starting index for slice. Can be omitted. See more examples below.
Ending index for slice (not included). Can be omitted. See more examples below.
Step between indexes of slice. Can be omitted. See more examples below.
List to get values from.
```py Example
nums = [40, 41, 42, 43]
nums[1:3] = [50, 51, 52] # this implicitly calls `nums.__setslice__(1, 3, 1, [50, 51, 52])`
# and now `nums` are [40, 50, 51, 52, 43]
```
Method `__setslice__` should never be called directly, instead `list_obj[slice] = other_list` syntax should be used.
Returns a copy of the list.
Extends the list by appending elements from the given list.
List to concatenate with the current.
Returns a concatenation of two lists.
List to concatenate with the current.
```py Example
nums1 = [40, 41]
nums2 = [42, 43]
nums3 = nums1 + nums2 # this implicitly calls `nums1.__add__(nums2)`
```
Method `__add__` should never be called directly, instead `list1 + list2` syntax should be used.
Returns a concatenation of the list with `n` its copies.
How many copies of the list to concatenate.
```py Example
nums1 = [40, 41]
nums2 = nums1 * 3 # this implicitly calls `nums1.__mul__(3)`
# and now `nums2` is [40, 41, 40, 41, 40, 41]
```
Method `__mul__` should never be called directly, instead `lst * n` syntax should be used.
```py Example
# examples of list creation:
a = [1, 2, 3] # `a` has type `list[int]`
b = [1, 2, 3, 4.2] # `b` has type `list[float]`
c = ["a", "b", "c"] # `c` has type `list[str]`
d = [(1, "a"), (2, "b"), (3, "c")] # `d` has type `list[tuple[int, str]]`
e = [0, 1, 2, 3, 4, 5, 6, 7]
f = e[2:5] # `f` is `[2, 3, 4]`
g = e[:5] # `g` is `[0, 1, 2, 3, 4]`
h = e[2:] # `h` is `[2, 3, 4, 5, 6, 7]`
i = e[:] # `i` is a copy of `e`
j = e[1:7:2] # `j` is `[1, 3, 5]`
k = e[5:2:-1] # `k` is `[5, 4, 3]`
l = e[5::-1] # `l` is `[5, 4, 3, 2, 1, 0]`
m = e[::-1] # `m` is `[7, 6, 5, 4, 3, 2, 1, 0]`
```
***
### `NoneType`
*type*
Builtin Indie type (similar to Python's `NoneType` type).
***
### `str`
*type*
Built-in Indie type (similar to Python's).
Returns the length (the number of characters) of a `str`.
```py Example
s = 'foobar'
len(s) # returns 6 (this implicitly calls `s.__len__()`)
```
Method `__len__` should never be called directly, instead `len(str_obj)` syntax should be used.
Cast constructor for built-in Indie type. Returns a `str` version of object.
Value to cast from.
Cast constructor for built-in Indie type. Returns a `str` version of object.
Value to cast from.
Cast constructor for built-in Indie type. Returns a `str` version of object.
Value to cast from.
Cast constructor for built-in Indie type. Returns a `str` version of object.
Value to cast from.
Returns `True` if the string contains the given substring, otherwise `False`.
Substring to find in the string.
```py Example
my_bool = 'cd' in 'abcdef' # this implicitly calls `'abcdef'.__contains__('cd')`
```
Method `__contains__` should never be called directly, instead `str1 in str2` syntax should be used.
Returns a concatenation of two strings.
String to concatenate with the current.
```py Example
str1 = 'ab'
str2 = 'cf'
str3 = str1 + str2 # this implicitly calls `str1.__add__(str2)`
```
Method `__add__` should never be called directly, instead `str1 + str2` syntax should be used.
Returns a concatenation of the string with `n` its copies.
How many copies of the string to concatenate.
```py Example
my_str = 'abc'
my_str2 = 'abc' * 3 # this implicitly calls `'abc'.__mul__(3)`
# and now `my_str2` is 'abcabcabc'
```
Method `__mul__` should never be called directly, instead `my_str * n` syntax should be used.
Returns substring at given index.
Index of an element in the string.
```py Example
my_str = 'abc'
substr = my_str[1] # returns "b" (this implicitly calls `my_str.__getitem__(1)`)
```
Method `__getitem__` should never be called directly, instead `my_str[key]` syntax should be used.
Returns a slice of the string elements.
Starting index for slice. Can be omitted. See more examples below.
Ending index for slice (not included). Can be omitted. See more examples below.
Step between indexes of slice. Can be omitted. See more examples below.
```py Example
my_str = '0123'
meaning_of_life = my_str[1:3] # returns '12' (this implicitly calls `my_str.__getslice__(1, 3, 1)`)
```
Method `__getslice__` should never be called directly, instead `str_obj[slice]` syntax should be used.
Returns the string with the first letter capitalized.
Centers the string within the specified width using a fill character.
Length of the result string.
Fill character.
Returns the count of non-overlapping occurrences of a substring within \[start, end].
Value to search for.
Start index to search.
End index to search.
Returns `True` if the string ends with the suffix, otherwise `False`.
Value to check if the end of the string equals.
Start index to check the end of the string.
End index to check the end of the string.
Returns the lowest index where the substring is found.
Value to search for.
Start index for searching.
End index for searching.
Use the `find()` method to get the position of a substring. To check for its presence, use the `in` operator.
Returns the lowest index of the substring within \[start, end], raising an error if not found.
Value to search for.
Start index for searching.
End index for searching.
Returns `True` if the string contains only alphabetic characters and is not empty; otherwise, `False`.
Returns `True` if all cased characters are lowercase and there is at least one, otherwise `False`.
Returns `True` if the string contains only whitespace and is not empty, otherwise `False`.
Returns `True` if all cased characters are uppercase and there is at least one, otherwise `False`.
Returns a string that joins the elements of the list, using the string as a separator.
List of strings to join.
Left justifies the string within the specified width, padding with the fill character. Returns the original string if width is less than or equal to its length.
Length of the result string.
Fill character.
Returns a copy of the string with all cased characters in lowercase.
Returns a copy of the string with leading characters removed.
Characters to remove.
Splits the string at the first occurrence of sep and returns a list with the parts before, the separator, and after.
String separator value.
Returns a copy of the string with all occurrences of old replaced by new, or the first count occurrences if specified.
Old value to search.
New value to replace with.
How many occurrences to replace.
Returns the highest index of sub within \[start, end], or -1 if not found.
Value to search for.
Start index for searching.
End index for searching.
Returns the highest index of sub within \[start, end], raising an error if not found.
Value to search for.
Start index for searching.
End index for searching.
Right justifies the string within the specified width, padding with the fill character. Returns the original string if width is less than or equal to its length.
Length of the result string.
Fill character.
Splits the string at the last occurrence of sep and returns a list with the parts before, the separator, and after.
String separator value.
Splits the string into words using sep as the delimiter, with an optional maxsplit from the right.
String separator value.
Number of splits.
Returns a copy of the string with trailing characters removed.
Characters to remove.
Splits the string into words using sep as the delimiter, with at most maxsplit splits, resulting in up to maxsplit+1 elements.
String separator value.
Number of splits.
Returns `True` if string starts with the prefix, otherwise `False`.
Value to check if the beginning of the string equals.
Start index to check the beginning of the string.
End index to check the beginning of the string.
Returns a string with the leading and trailing characters removed.
Characters to remove.
Returns a copy of the string with case swapped.
Returns a copy of the string with all cased characters in uppercase.
```py Example
# examples of slices extraction:
a = '01234567'
b = a[2:5] # `b` is '234'
c = a[:5] # `c` is '01234'
d = a[2:] # `d` is '234567'
e = a[:] # `e` is a copy of `a`
f = a[1:7:2] # `f` is '135'
g = a[5:2:-1] # `g` is '543'
h = a[5::-1] # `h` is '543210'
i = a[::-1] # `i` is '76543210'
```
***
### `tuple[...]`
*type*
Built-in Indie type (similar to Python's).
***
# Package datetime
Source: https://takeprofit.com/docs/indie/Library-reference/package-datetime
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
The datetime package supplies classes for manipulating dates and times.
See description in the [official Python docs](https://docs.python.org/3.10/library/datetime.html).
***
## Types
### `datetime`
*type*
Represents date and time information.
The year value of the datetime object.
The month value of the datetime object.
The day value of the datetime object.
The hour value of the datetime object.
The minute value of the datetime object.
The second value of the datetime object.
The microsecond value of the datetime object.
Class constructor (initializer for the data type).
Year value.
Month value.
Day value.
Hour value.
Minute value.
Second value.
Microsecond value.
Returns the total number of seconds since the Unix epoch.
Returns the day of the week as an integer, where Monday is 0 and Sunday is 6.
`+` operator for `datetime` objects.
Timedelta to add to the current datetime.
`-` operator for `datetime` objects.
Timedelta to subtract from the current datetime.
`-` operator for `datetime` objects.
Datetime to subtract from the current datetime.
Returns the UTC datetime corresponding to the POSIX timestamp.
Timestamp in UTC.
Returns a datetime corresponding to `date_string`, parsed according to `format`.
Datetime to parse.
Datetime format. Supported codes: `%Y`, `%y`, `%m`, `%b`, `%d`, `%H`, `%I`, `%M`, `%S`, `%p`, `%f`, `%z`. See more details [here](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes).
***
### `time`
*type*
Represents a time of day, independent of any particular day.
The hour value of the time object.
The minute value of the time object.
The second value of the time object.
The microsecond value of the time object.
Class constructor (initializer for the data type).
Hour value.
Minute value.
Second value.
Microsecond value.
`+` operator for `time` objects.
Timedelta to add to the current time.
`-` operator for `time` objects.
Timedelta to subtract from the current time.
***
### `timedelta`
*type*
A timedelta object represents a duration, the difference between two datetimes.
The days value of the timedelta object.
The seconds value of the timedelta object.
The microseconds value of the timedelta object.
Class constructor (initializer for the data type).
Number of days.
Number of seconds.
Number of microseconds.
Number of milliseconds.
Number of minutes.
Number of hours.
Number of weeks.
Returns the total number of seconds contained in the duration.
***
# Package indie
Source: https://takeprofit.com/docs/indie/Library-reference/package-indie
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Main package of Indie language.
***
## Decorators
### `@algorithm()`
*decorator*
Decorates a function, making it a *series processor* algorithm. Such algorithms are specifically designed to process series of data, like close prices of an instrument of a candle chart. One way of using such an algorithm is to call `new` static method, read more [here](/indie/How-Indies-syntactic-sugar-works#algorithmnew-method).
Most of the functions in the `indie.algorithms` package are decorated with `@indie.algorithm` decorator. Read more about it in [Series processors](/indie/Algorithms-for-series-processing) chapter.
See also: [`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
***
### `@band()`
*decorator*
Use this decorator to add a band (two horizontal lines usually with a semi-transparent fill in between them) to indicator.
Value of the first horizontal line of a band on a vertical scale of an indicator.
Value of the second horizontal line of a band on a vertical scale of an indicator.
Human readable title which is visible in the indicator's Settings panel.
Color of the background.
Color of the plot on a chart. This color can be overwritten if the plot is a multicolored one. Example of an indicator with a multicolored plot is *Awesome Oscillator (AO)*.
Style of the line. It is represented as enum value of type `line_style`.
Width of the line.
```py Example
@indicator('Band example')
@band(145, 155, line_color=color.RED, line_width=4)
def Main(self):
return self.close[0]
```
See also: [`@level()`](/indie/Library-reference/package-indie#decor_level)
***
### `@indicator()`
*decorator*
Decorator that should be applied to the `Main` entry point of any indicator.
Abbreviated title of the indicator.
Whether or not to overlay the indicator over the main pane of the chart. The main pane of a chart is the one with the main instrument on it.
Formatting style of indicator output values represented as enum value of type `format`.
Number of digits after floating point for indicator output values.
See also: [`@sec_context()`](/indie/Library-reference/package-indie#decor_sec_context)
***
### `@level()`
*decorator*
Decorator that is used to create a level (horizontal line) in an indicator.
Value of the level on a vertical scale of an indicator.
Human readable title which is visible in the indicator's Settings panel.
Color of the plot on a chart. This color can be overwritten if the plot is a multicolored one. Example of an indicator with a multicolored plot is *Awesome Oscillator (AO)*.
Style of the line. It is represented as enum value of type `line_style`.
Width of the line.
```py Example
@indicator('Level example')
@level(150, line_color=color.RED, line_width=4)
def Main(self):
return self.close[0]
```
See also: [`@band()`](/indie/Library-reference/package-indie#decor_band)
***
### `@param_ref()`
*decorator*
Declares an input parameter for `@sec_context` function that is linked to the input parameter of `Main` by `id`.
Name of `Main` function or class parameter bound to the input parameter.
```py Example
@sec_context
@param_ref('referenced_param')
def SecMain(self, referenced_param) -> float:
# Use referenced_param variable...
@indicator('Referenced param example')
@param.int('referenced_param', default=50)
class Main(MainContext):
def __init__(self):
self._calc_on_result = self.calc_on(time_frame=TimeFrame.from_str('1D'), sec_context=SecMain)
def calc(self):
return self._calc_on_result[0]
```
See also: [`@sec_context()`](/indie/Library-reference/package-indie#decor_sec_context) [`param`](/indie/Library-reference/package-indie#class_param)
***
### `param`
*type*
Class with decorators of indicator input parameters of various types.
Declares a bool input parameter of indicator. Values of input parameters can be changed in indicator's Settings panel. Input parameters are used in combination with corresponding parameter declaration in `Main` entry point.
Name of `Main` function or class parameter bound to the input parameter.
Default value for the parameter in settings pane.
Human readable title which is visible in the indicator's Settings panel.
```py Example
@param.bool('is_something_enabled', default=False)
def Main(self, is_something_enabled):
# Use is_something_enabled variable...
```
Declares an integer input parameter of indicator. Values of input parameters can be changed in indicator's Settings panel. Input parameters are used in combination with corresponding parameter declaration in `Main` entry point.
Name of `Main` function or class parameter bound to the input parameter.
Default value for the parameter in settings pane.
Minimum value of the parameter.
Maximum value of the parameter.
Step between values of the parameter.
Human readable title which is visible in the indicator's Settings panel.
```py Example
@param.int('meaning_of_life', default=42)
def Main(self, meaning_of_life):
# Use meaning_of_life variable...
```
Declares a float input parameter of indicator. Values of input parameters can be changed in indicator's Settings panel. Input parameters are used in combination with corresponding parameter declaration in `Main` entry point.
Name of `Main` function or class parameter bound to the input parameter.
Default value for the parameter in settings pane.
Minimum value of the parameter.
Maximum value of the parameter.
Step between values of the parameter.
Human readable title which is visible in the indicator's Settings panel.
```py Example
@param.float('speed_of_light', default=299_792.458)
def Main(self, speed_of_light):
# Use speed_of_light variable...
```
Declares a str input parameter of indicator. Values of input parameters can be changed in indicator's Settings panel. Input parameters are used in combination with corresponding parameter declaration in `Main` entry point.
Name of `Main` function or class parameter bound to the input parameter.
Default value for the parameter in settings pane.
List of the possible values of the parameter.
Human readable title which is visible in the indicator's Settings panel.
```py Example
@param.str('name', default='Lisa', options=['Homer', 'Marge', 'Bart', 'Lisa', 'Maggie'])
def Main(self, name):
# Use name variable...
```
If `options` parameter is used then in Settings panel there will be a combobox widget for changing value of this input.
Declares a source input parameter of indicator. Values of input parameters can be changed in indicator's Settings panel. Input parameters are used in combination with corresponding parameter declaration in `Main` entry point.
Name of `Main` function or class parameter bound to the input parameter.
Default value for the parameter in settings pane.
List of the possible values of the parameter.
Human readable title which is visible in the indicator's Settings panel.
```py Example
@param.source('src', default=source.CLOSE, options=[source.CLOSE, source.HL2, source.HLC3, source.OHLC4])
def Main(self, src):
# Use src variable...
```
Even if `options` parameter is not used then in Settings panel nevertheless there will be a combobox widget with all possible values from the `source` enum.
See also: [`param`](/indie/Library-reference/package-indie#class_param) [`source`](/indie/Library-reference/package-indie#enum_source)
Declares a time frame input parameter of indicator. Values of input parameters can be changed in indicator's Settings panel. Input parameters are used in combination with corresponding parameter declaration in `Main` entry point.
Name of `Main` function or class parameter bound to the input parameter.
Default value for the parameter in settings pane.
List of the possible values of the parameter.
Human readable title which is visible in the indicator's Settings panel.
```py Example
@param.time_frame('time_frame', default='30m', options=['1m', '30m', '1h', '4h', '1D', '1W', '1M', '1Y'])
def Main(self, time_frame):
# Use time_frame variable...
```
The type of `time_frame` in the example variable will be `TimeFrame`. But please note, that for the convenience, default value has `str` type. String representation of `TimeFrame` has a form of `[m|h|D|W|M|Y]` where suffixes mean: `m` - minutes, `h` - hours, `D` - days, `W` - weeks, `M` - months, `Y` - years. If `options` parameter is used then in Settings panel there will be a combobox widget for changing value of this input.
See also: [`TimeFrame`](/indie/Library-reference/package-indie#class_TimeFrame)
***
### `@sec_context()`
*decorator*
Decorates a function, making it a secondary `Main` entry point for additional instrument of an indicator. Additional instruments are requested with the help of `Context.calc_on` function and this decorator.
```py Example
# indie:lang_version = 5
from indie import indicator, sec_context, param
@sec_context
def Main2(self):
return self.high[0], self.low[0]
@indicator('Minimal calc_on example', overlay_main_pane=True)
@param.time_frame('sec_time_frame', default='1D')
class Main(MainContext):
def __init__(self, sec_time_frame):
self._sec_high, self._sec_low = self.calc_on(time_frame=sec_time_frame, sec_context=Main2)
def calc(self):
return self._sec_high[0], self._sec_low[0]
```
More info on this topic you can find in [Request additional instruments](/indie/Request-additional-instruments) chapter.
See also: [`@indicator()`](/indie/Library-reference/package-indie#decor_indicator) [`SecContext`](/indie/Library-reference/package-indie#class_SecContext) [`Context.calc_on()`](/indie/Library-reference/package-indie#method_Context_calc_on)
***
## Types
### `Algorithm`
*type*
Base class for the classes that perform some processing of series data.
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
See also: [`@algorithm()`](/indie/Library-reference/package-indie#decor_algorithm) [`MainContext`](/indie/Library-reference/package-indie#class_MainContext) [`SecContext`](/indie/Library-reference/package-indie#class_SecContext)
***
### `Color`
*type*
Data type to represent color.
Creates a new Color instance with the given transparency applied to the existing color.
Alpha channel (component) of color which ranges from `0.0` (fully transparent) to `1.0` (fully opaque).
```py Example
half_transparent_red = color.RED(0.5) # This implicitly calls `color.RED.__call__(0.5)`
```
Method `__call__` should never be called directly, instead `color_obj(value)` syntax should be used.
See also: [`color`](/indie/Library-reference/package-indie-color)
***
### `Context`
*type*
Data type that represents an instrument with OHLCV series values and other related information.
Series of timestamps (as unix time UTC seconds) of the context's instrument. Every timestamp corresponds to start time of some bar on a chart.
Series of 'open' prices of the context's instrument.
Series of 'high' prices of the context's instrument.
Series of 'low' prices of the context's instrument.
Series of 'close' prices of the context's instrument.
Series of 'volume' values of the context's instrument.
Series of '(high + low) / 2' values of the context's instrument.
Series of '(high + low + close) / 3' values of the context's instrument.
Series of '(open + high + low + close) / 4' values of the context's instrument.
Information about the context's instrument.
Index of a last (current) bar in this context's instrument which the indicator has received. The very first bar has index equal to `0` and this is the oldest bar.
Current total number of bars in this context's instrument which the indicator has received. It is always true that `self.bar_count` is equal to `self.bar_index + 1`.
Flag that is `True` if the current bar is a historical bar or it is a final update for a realtime bar.
Flag that is `True` if the current bar is a historical bar.
Flag that is `True` if the current bar is the last bar in the history or it is a realtime bar.
Flag that is `True` if the current bar is the last bar of the historical part of prices data.
Flag that is `True` if the current bar is a historical bar or it is a first update for a realtime bar.
Flag that is `True` if the last (current) bar is a realtime bar.
Time frame of the context's instrument.
Trading session of the context's instrument.
Requests additional instrument (creates a secondary context object for it) for indicator and returns one or more `SeriesF` objects which match with the arity of values that `sec_context` function returns. All the returned series values are merged into the timescale of current context's instrument.
Function decorated with `@indie.sec_context`. This function has the same semantics as Indie `Main`, but for additional instrument (not the main one).
Alias for exchange of additional instrument. If omitted, then the exchange of the current context's instrument will be used.
Ticker of an additional instrument. If omitted, then the ticker of the current context's instrument will be used.
Time frame of additional instrument. If omitted, then the time frame of current context's instrument will be used. At the moment it is allowed to request only time frames which are higher or equal to the time frame of current context's instrument.
If this flag is true, then when calculating history, the bars of the secondary context are merged with the bars of the current context based on their opening time. Such a data merge strategy may result in unintended use of data from future history.
At least one of optional arguments (`exchange`, `ticker` or `time_frame`) must be provided. More info about this function as well as code examples you may find in [Request additional instruments](/indie/Request-additional-instruments) chapter.
See also: [`@sec_context()`](/indie/Library-reference/package-indie#decor_sec_context) [`SecContext`](/indie/Library-reference/package-indie#class_SecContext)
Creates a `MutSeriesF` (an alias for `MutSeries[float]`) object, which is a container for `float` values in Indie code. The main feature of the `MutSeriesF` container is its ability to store (or 'remember') the historical values of a variable. These values can be accessed later using the square brackets operator (via the `__getitem__` method).
Default value that will be used if an element at the specified index cannot be extracted.
Number of elements that `MutSeriesF` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator. `MutSeriesF` objects also have a method `request_size(new_size: int)` which can be used to expand the size explicitly.
See also: [`MutSeriesF`](/indie/Library-reference/package-indie#class_MutSeriesF)
Creates a `MutSeries[T]` object, which is a container for `T` values in Indie code. The main feature of the `MutSeries[T]` container is its ability to store (or 'remember') the historical values of a variable. These values can be accessed later using the square brackets operator (via the `__getitem__` method).
Default value that will be used if an element at the specified index cannot be extracted.
Number of elements that `MutSeries` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator. `MutSeries` objects also have a method `request_size(new_size: int)` which can be used to expand the size explicitly.
Creates a `Var[T]` object, which is a container for `T` value in Indie code. The main feature of the `Var[T]` container is its ability to rollback the value of the variable when a new realtime update appears to its value after the previous bar.
Value that is written into `Var` object only once after the `Var` object was created.
Detects whether the current bar is the first bar of a new trading session (extended session included). Returns `True` if the current bar is the first bar of the trading session or `False` if the current bar is not the first in the session or if no session has started.
The function will return `False` if the first bar of the session does not exist or is unavailable (e.g., due to data gaps or missing information).
Detects whether the current bar is the first bar of the regular trading session (excluding pre-market session). Returns `True` if the current bar is the first bar of the regular trading session or `False` if the current bar is not the first in the regular session or if no session has started.
The function will return `False` if the first bar of the regular session does not exist or is unavailable (e.g., due to data gaps or missing information).
Detects whether the current bar is the last bar of the trading session (extended session included). Returns `True` if the current bar is the last bar of the trading session or `False` if the current bar is not the last in the session.
The function will return `False` if the session ends without a valid last bar (e.g., due to missing data).
Detects whether the current bar is the last bar of the regular trading session (excluding after-hours session). Returns `True` if the current bar is the last bar of the regular trading session or `False` if the current bar is not the last in the regular session.
The function will return `False` if the session ends without a valid last bar (e.g., due to missing data).
See also: [`MainContext`](/indie/Library-reference/package-indie#class_MainContext) [`SecContext`](/indie/Library-reference/package-indie#class_SecContext) [`SymbolInfo`](/indie/Library-reference/package-indie#class_SymbolInfo) [`Series[T]`](/indie/Library-reference/package-indie#class_Series) [`MutSeries[T]`](/indie/Library-reference/package-indie#class_MutSeries) [`TradingSession`](/indie/Library-reference/package-indie#class_TradingSession)
***
### `IndieError`
*type*
Data type for Indie errors.
Class constructor (initializer for the data type).
Error message.
***
### `MainContext`
*type*
Base class for the class that represents main context.
[`Context`](/indie/Library-reference/package-indie#class_Context)
Series of timestamps (as unix time UTC seconds) of the context's instrument. Every timestamp corresponds to start time of some bar on a chart.
Series of 'open' prices of the context's instrument.
Series of 'high' prices of the context's instrument.
Series of 'low' prices of the context's instrument.
Series of 'close' prices of the context's instrument.
Series of 'volume' values of the context's instrument.
Series of '(high + low) / 2' values of the context's instrument.
Series of '(high + low + close) / 3' values of the context's instrument.
Series of '(open + high + low + close) / 4' values of the context's instrument.
Information about the context's instrument.
Index of a last (current) bar in this context's instrument which the indicator has received. The very first bar has index equal to `0` and this is the oldest bar.
Current total number of bars in this context's instrument which the indicator has received. It is always true that `self.bar_count` is equal to `self.bar_index + 1`.
Flag that is `True` if the current bar is a historical bar or it is a final update for a realtime bar.
Flag that is `True` if the current bar is a historical bar.
Flag that is `True` if the current bar is the last bar in the history or it is a realtime bar.
Flag that is `True` if the current bar is the last bar of the historical part of prices data.
Flag that is `True` if the current bar is a historical bar or it is a first update for a realtime bar.
Flag that is `True` if the last (current) bar is a realtime bar.
Time frame of the context's instrument.
Trading session of the context's instrument.
Requests additional instrument (creates a secondary context object for it) for indicator and returns one or more `SeriesF` objects which match with the arity of values that `sec_context` function returns. All the returned series values are merged into the timescale of current context's instrument.
Function decorated with `@indie.sec_context`. This function has the same semantics as Indie `Main`, but for additional instrument (not the main one).
Alias for exchange of additional instrument. If omitted, then the exchange of the current context's instrument will be used.
Ticker of an additional instrument. If omitted, then the ticker of the current context's instrument will be used.
Time frame of additional instrument. If omitted, then the time frame of current context's instrument will be used. At the moment it is allowed to request only time frames which are higher or equal to the time frame of current context's instrument.
If this flag is true, then when calculating history, the bars of the secondary context are merged with the bars of the current context based on their opening time. Such a data merge strategy may result in unintended use of data from future history.
At least one of optional arguments (`exchange`, `ticker` or `time_frame`) must be provided. More info about this function as well as code examples you may find in [Request additional instruments](/indie/Request-additional-instruments) chapter.
See also: [`@sec_context()`](/indie/Library-reference/package-indie#decor_sec_context) [`SecContext`](/indie/Library-reference/package-indie#class_SecContext)
Creates a `MutSeriesF` (an alias for `MutSeries[float]`) object, which is a container for `float` values in Indie code. The main feature of the `MutSeriesF` container is its ability to store (or 'remember') the historical values of a variable. These values can be accessed later using the square brackets operator (via the `__getitem__` method).
Default value that will be used if an element at the specified index cannot be extracted.
Number of elements that `MutSeriesF` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator. `MutSeriesF` objects also have a method `request_size(new_size: int)` which can be used to expand the size explicitly.
See also: [`MutSeriesF`](/indie/Library-reference/package-indie#class_MutSeriesF)
Creates a `MutSeries[T]` object, which is a container for `T` values in Indie code. The main feature of the `MutSeries[T]` container is its ability to store (or 'remember') the historical values of a variable. These values can be accessed later using the square brackets operator (via the `__getitem__` method).
Default value that will be used if an element at the specified index cannot be extracted.
Number of elements that `MutSeries` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator. `MutSeries` objects also have a method `request_size(new_size: int)` which can be used to expand the size explicitly.
Creates a `Var[T]` object, which is a container for `T` value in Indie code. The main feature of the `Var[T]` container is its ability to rollback the value of the variable when a new realtime update appears to its value after the previous bar.
Value that is written into `Var` object only once after the `Var` object was created.
Detects whether the current bar is the first bar of a new trading session (extended session included). Returns `True` if the current bar is the first bar of the trading session or `False` if the current bar is not the first in the session or if no session has started.
The function will return `False` if the first bar of the session does not exist or is unavailable (e.g., due to data gaps or missing information).
Detects whether the current bar is the first bar of the regular trading session (excluding pre-market session). Returns `True` if the current bar is the first bar of the regular trading session or `False` if the current bar is not the first in the regular session or if no session has started.
The function will return `False` if the first bar of the regular session does not exist or is unavailable (e.g., due to data gaps or missing information).
Detects whether the current bar is the last bar of the trading session (extended session included). Returns `True` if the current bar is the last bar of the trading session or `False` if the current bar is not the last in the session.
The function will return `False` if the session ends without a valid last bar (e.g., due to missing data).
Detects whether the current bar is the last bar of the regular trading session (excluding after-hours session). Returns `True` if the current bar is the last bar of the regular trading session or `False` if the current bar is not the last in the regular session.
The function will return `False` if the session ends without a valid last bar (e.g., due to missing data).
See also: [`SecContext`](/indie/Library-reference/package-indie#class_SecContext) [`Context`](/indie/Library-reference/package-indie#class_Context) [`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
***
### `MutSeries[T]`
*type*
Generic data type that represents read-write series of values of type `T`. Type `T` can be float, int, str, or almost any other type.
```py
MutSeriesF = MutSeries[float]
```
[`Series[T]`](/indie/Library-reference/package-indie#class_Series)
Sets value of `MutSeries[T]` object at the specified index.
Index to assign value at.
New value.
```py Example
ms = MutSeries[float].new(init=0)
ms[0] = 42 # This implicitly calls `ms.__setitem__(0, 42)`
```
(1) The index must be equal to 0 (because historical values cannot be updated), otherwise the function will raise an error at runtime. Yes, this looks very weird and maybe it would be much better just to have a method `MutSeriesF.set_last(value: float)` but we like the syntax of square brackets. Maybe this will be fixed in the future versions of Indie, hard to say for sure. (2) Method `__setitem__` should never be called directly, instead syntax `series_obj[index] = value` should be used.
Recalculates a `MutSeries[T]` object. In most cases, you can simply use the `s[i] = ...` syntax instead, but this method allows you to pass an initialization value to the series.
Value that is written into the most recent element of the `MutSeries` every time `MutSeries.new` function is executed.
Value that is written into the most recent element of the `MutSeries` object only once after the `MutSeries` object was created.
Number of elements that `MutSeries` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator. `MutSeries` objects also have a method `request_size(new_size: int)` which can be used to expand the size explicitly.
Creates a `MutSeries[T]` object, which is a container for `T` values in Indie code. The main feature of the `MutSeries[T]` container is its ability to store (or 'remember') the historical values of a variable. These values can be accessed later using the square brackets operator (via the `__getitem__` method).
Value that is written into the most recent element of the `MutSeries` every time `MutSeries.new` function is executed.
Value that is written into the most recent element of the `MutSeries` object only once after the `MutSeries` object was created.
Number of elements that `MutSeries` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator. `MutSeries` objects also have a method `request_size(new_size: int)` which can be used to expand the size explicitly.
See also: [`Context.new_mut_series()`](/indie/Library-reference/package-indie#method_Context_new_mut_series)
Returns value of `Series[T]` object at the specified index or given `default` if the value is missing.
Offset to extract value at.
Default value that will be used if an element at the specified index cannot be extracted.
If `False` then `get` method raises an error on any `offset < 0`. If `True` then `get` method returns `default` value on negative offsets too. Default value is `False`.
Expands the capacity of `Series[T]` object (number of elements that `Series[T]` object should store in memory).
Number of elements that `SeriesF` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator.
Returns value of `Series[T]` object at the specified index. If the value is missing, then the default value of type `T` is returned (e.g. `math.nan` if `T` is float).
Index to extract value at.
```py Example
@indicator('Example')
def Main(self):
return self.close[0] # This implicitly calls `self.close.__getitem__(0)`
```
Method `__getitem__` should never be called directly. Instead syntax `series_obj[index]` should be used.
Returns length (number of elements) of a `Series[T]` object.
```py Example
l = len(self.close) # this implicitly calls `self.close.__len__()`
```
Method `__len__` should never be called directly. Instead syntax `len(series_obj)` should be used.
See also: [`Context.new_mut_series()`](/indie/Library-reference/package-indie#method_Context_new_mut_series) [`Series[T]`](/indie/Library-reference/package-indie#class_Series)
***
### `Optional[T]`
*type*
Builtin Indie type (similar to Python's `typing.Optional`).
Class constructor (initializer for the data type).
Value to cast from.
Class constructor (initializer for the data type).
Returns value of `indie.Optional[T]` object. Raises a runtime error if the optional object is `None`.
Returns value of `indie.Optional[T]` object or given `default` if the optional object is `None`.
Default value that will be used if there is no value.
Casts `Optional` object to bool.
This method is present for `Optional[T]` only if `T` can be converted to `bool`.
Returns `True` if the optional value is `None`, otherwise `False`.
```py Example
my_val: Optional[int] = 4
my_bool = my_val is None
```
Method `__isnone__` should never be called directly, instead `val is None` syntax should be used.
***
### `SecContext`
*type*
Base class for the classes that represent additional contexts besides the main one.
[`Context`](/indie/Library-reference/package-indie#class_Context)
Series of timestamps (as unix time UTC seconds) of the context's instrument. Every timestamp corresponds to start time of some bar on a chart.
Series of 'open' prices of the context's instrument.
Series of 'high' prices of the context's instrument.
Series of 'low' prices of the context's instrument.
Series of 'close' prices of the context's instrument.
Series of 'volume' values of the context's instrument.
Series of '(high + low) / 2' values of the context's instrument.
Series of '(high + low + close) / 3' values of the context's instrument.
Series of '(open + high + low + close) / 4' values of the context's instrument.
Information about the context's instrument.
Index of a last (current) bar in this context's instrument which the indicator has received. The very first bar has index equal to `0` and this is the oldest bar.
Current total number of bars in this context's instrument which the indicator has received. It is always true that `self.bar_count` is equal to `self.bar_index + 1`.
Flag that is `True` if the current bar is a historical bar or it is a final update for a realtime bar.
Flag that is `True` if the current bar is a historical bar.
Flag that is `True` if the current bar is the last bar in the history or it is a realtime bar.
Flag that is `True` if the current bar is the last bar of the historical part of prices data.
Flag that is `True` if the current bar is a historical bar or it is a first update for a realtime bar.
Flag that is `True` if the last (current) bar is a realtime bar.
Time frame of the context's instrument.
Trading session of the context's instrument.
Requests additional instrument (creates a secondary context object for it) for indicator and returns one or more `SeriesF` objects which match with the arity of values that `sec_context` function returns. All the returned series values are merged into the timescale of current context's instrument.
Function decorated with `@indie.sec_context`. This function has the same semantics as Indie `Main`, but for additional instrument (not the main one).
Alias for exchange of additional instrument. If omitted, then the exchange of the current context's instrument will be used.
Ticker of an additional instrument. If omitted, then the ticker of the current context's instrument will be used.
Time frame of additional instrument. If omitted, then the time frame of current context's instrument will be used. At the moment it is allowed to request only time frames which are higher or equal to the time frame of current context's instrument.
If this flag is true, then when calculating history, the bars of the secondary context are merged with the bars of the current context based on their opening time. Such a data merge strategy may result in unintended use of data from future history.
At least one of optional arguments (`exchange`, `ticker` or `time_frame`) must be provided. More info about this function as well as code examples you may find in [Request additional instruments](/indie/Request-additional-instruments) chapter.
See also: [`@sec_context()`](/indie/Library-reference/package-indie#decor_sec_context) [`SecContext`](/indie/Library-reference/package-indie#class_SecContext)
Creates a `MutSeriesF` (an alias for `MutSeries[float]`) object, which is a container for `float` values in Indie code. The main feature of the `MutSeriesF` container is its ability to store (or 'remember') the historical values of a variable. These values can be accessed later using the square brackets operator (via the `__getitem__` method).
Default value that will be used if an element at the specified index cannot be extracted.
Number of elements that `MutSeriesF` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator. `MutSeriesF` objects also have a method `request_size(new_size: int)` which can be used to expand the size explicitly.
See also: [`MutSeriesF`](/indie/Library-reference/package-indie#class_MutSeriesF)
Creates a `MutSeries[T]` object, which is a container for `T` values in Indie code. The main feature of the `MutSeries[T]` container is its ability to store (or 'remember') the historical values of a variable. These values can be accessed later using the square brackets operator (via the `__getitem__` method).
Default value that will be used if an element at the specified index cannot be extracted.
Number of elements that `MutSeries` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator. `MutSeries` objects also have a method `request_size(new_size: int)` which can be used to expand the size explicitly.
Creates a `Var[T]` object, which is a container for `T` value in Indie code. The main feature of the `Var[T]` container is its ability to rollback the value of the variable when a new realtime update appears to its value after the previous bar.
Value that is written into `Var` object only once after the `Var` object was created.
Detects whether the current bar is the first bar of a new trading session (extended session included). Returns `True` if the current bar is the first bar of the trading session or `False` if the current bar is not the first in the session or if no session has started.
The function will return `False` if the first bar of the session does not exist or is unavailable (e.g., due to data gaps or missing information).
Detects whether the current bar is the first bar of the regular trading session (excluding pre-market session). Returns `True` if the current bar is the first bar of the regular trading session or `False` if the current bar is not the first in the regular session or if no session has started.
The function will return `False` if the first bar of the regular session does not exist or is unavailable (e.g., due to data gaps or missing information).
Detects whether the current bar is the last bar of the trading session (extended session included). Returns `True` if the current bar is the last bar of the trading session or `False` if the current bar is not the last in the session.
The function will return `False` if the session ends without a valid last bar (e.g., due to missing data).
Detects whether the current bar is the last bar of the regular trading session (excluding after-hours session). Returns `True` if the current bar is the last bar of the regular trading session or `False` if the current bar is not the last in the regular session.
The function will return `False` if the session ends without a valid last bar (e.g., due to missing data).
See also: [`@sec_context()`](/indie/Library-reference/package-indie#decor_sec_context) [`MainContext`](/indie/Library-reference/package-indie#class_MainContext) [`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
***
### `Series[T]`
*type*
Generic data type that represents read only series of values of type `T`. Type `T` can be float, int, str, or almost any other type.
```py
SeriesF = Series[float]
```
Returns value of `Series[T]` object at the specified index or given `default` if the value is missing.
Offset to extract value at.
Default value that will be used if an element at the specified index cannot be extracted.
If `False` then `get` method raises an error on any `offset < 0`. If `True` then `get` method returns `default` value on negative offsets too. Default value is `False`.
Expands the capacity of `Series[T]` object (number of elements that `Series[T]` object should store in memory).
Number of elements that `SeriesF` object should store in memory. Default and possible minimum size is 2, which means that series of `size = 2` stores in memory value at the time of the last candle and value at the time of previous candle. Size is automatically expanded during history calculation of an indicator.
Returns value of `Series[T]` object at the specified index. If the value is missing, then the default value of type `T` is returned (e.g. `math.nan` if `T` is float).
Index to extract value at.
```py Example
@indicator('Example')
def Main(self):
return self.close[0] # This implicitly calls `self.close.__getitem__(0)`
```
Method `__getitem__` should never be called directly. Instead syntax `series_obj[index]` should be used.
Returns length (number of elements) of a `Series[T]` object.
```py Example
l = len(self.close) # this implicitly calls `self.close.__len__()`
```
Method `__len__` should never be called directly. Instead syntax `len(series_obj)` should be used.
See also: [`MutSeries[T]`](/indie/Library-reference/package-indie#class_MutSeries) [`Context`](/indie/Library-reference/package-indie#class_Context)
***
### `SymbolInfo`
*type*
Data type to represent information about the context's instrument.
Ticker of the context's instrument.
Exchange code of the context's instrument. For stocks it is a [MIC](https://en.wikipedia.org/wiki/Market_Identifier_Code). For crypto instruments it is just some identifier, not commonly recognized as MIC but unique within TakeProfit. For example, `exchange_code` for the New York Stock Exchange, Inc. is `'XNYS'`.
Commonly recognized (but not exactly standardized) alias for an exchange. For example, an alias for the New York Stock Exchange, Inc. is `'NYSE'`. In most cases exchange alias matches with the exchange acronym (see ISO10383).
Price precision of the context's instrument. For example, price precision of `100` means that prices have two digits after the floating point.
Absolute value of a minimal movement of a price of the context's instrument in corresponding currency.
Name of the exchange timezone of the context's instrument. For example, `'America/New_York'`.
See also: [`Context`](/indie/Library-reference/package-indie#class_Context)
***
### `TimeFrame`
*type*
Data type that represents time frame.
Class constructor (initializer for the data type).
Numeric part of time frame.
Unit of time frame, can be 'm', 'h', 'D', 'W' or 'M'.
Converts `TimeFrame` object to corresponding number of minutes. Month is always considered to be of 30 days long, and year is always of 365 days long.
Converts string representation of time frame to `TimeFrame` type. String representation of `TimeFrame` has a form of `[m|h|D|W|M|Y]` where suffixes mean: `m` - minutes, `h` - hours, `D` - days, `W` - weeks, `M` - months, `Y` - years. For example `TimeFrame.from_str('15m')` creates a `TimeFrame` object which corresponds to 15 minute time frame.
String representation of time frame.
***
### `TradingSession`
*type*
Data type to represent different trading periods within a day, including pre-market, regular, and after-hours sessions. Each period is defined by its own schedule.
Schedule instance that defines the rules and exceptions for the pre-market trading session.
Schedule instance that defines the rules and exceptions for the regular trading session.
Schedule instance that defines the rules and exceptions for the after-hours trading session.
Schedule instance that defines the rules and exceptions for the extended session (pre-market + after-hours).
Checks whether a given timestamp falls within the defined trading session. Returns `True` if the timestamp falls within the trading session's active periods, otherwise returns `False`.
Timestamp to check in defined trading session.
Checks whether a given timestamp falls within the defined trading session. Returns `True` if the timestamp falls within the trading session's active periods, otherwise returns `False`.
Datetime to check in defined trading session.
Determines whether two timestamps fall within the same trading session period on the same day. Returns `True` if both timestamps fall within the same period of the trading session, even if they are in different calendar days. False if the timestamps belong to different periods within the trading session.
First timestamp to check.
Second timestamp to check.
This method checks if two timestamps, which may belong to different calendar days, are part of the same trading session period. It handles cases where a trading session spans across two consecutive days (e.g., a trading schedule that extends past midnight) and ensures both timestamps belong to the same logical period within the schedule.
Determines whether a given timestamp falls within a regular trading session.
Timestamp to check against the specific part of trading sessions.
Determines whether a given timestamp falls within an extended trading session (either pre-market or after-hours).
Timestamp to check against the specific part of trading sessions.
Returns `True` if the provided timestamp falls within either the pre-market or after-hours session. Returns `False` otherwise.
Determines whether a given timestamp falls within a pre-market trading session.
Timestamp to check against the specific part of trading sessions.
Determines whether a given timestamp falls within a after-hours trading session.
Timestamp to check against the specific part of trading sessions.
See also: [`Context`](/indie/Library-reference/package-indie#class_Context) [`Schedule`](/indie/Library-reference/package-indie-schedule#class_Schedule) [`ScheduleRule`](/indie/Library-reference/package-indie-schedule#class_ScheduleRule)
***
### `Var[T]`
*type*
Generic data type that represents a rollbackable container for value of type `T`. Type `T` can be float, int, str, or almost any other type.
Returns value of `Var[T]` object.
Sets value of `Var[T]` object.
New value that will be put to `Var` object.
Creates a `Var[T]` object, which is a container for `T` value in Indie code. The main feature of the `Var[T]` container is its ability to rollback the value of the variable when a new realtime update appears to its value after the previous bar.
Value that is written into `Var` object only once after the `Var` object was created.
See also: [`Context.new_var()`](/indie/Library-reference/package-indie#method_Context_new_var) [`MutSeries[T]`](/indie/Library-reference/package-indie#class_MutSeries)
***
## Enums
### `format`
*enum*
Enum-like class with constants that determine how to format the indicator value on the price scale.
Indicator output values are formatted same as values of the main chart instrument.
Indicator output values are formatted using fixed number of digits after the floating point. The number of digits is set with additional parameter `precision` of `@indicator()`. The `precision` param has effect only in combination with the `format.PRICE` format.
Indicator output values are formatted according to the rules of formatting large numbers, such as volumes of trades. For example `100500.0` will be formatted as `100.5K`.
See also: [`@indicator()`](/indie/Library-reference/package-indie#decor_indicator)
***
### `line_style`
*enum*
Enum-like class with constants of line styles.
Built-in line style constant that determines how the line is rendered.
Built-in line style constant that determines how the line is rendered.
Built-in line style constant that determines how the line is rendered.
See also: [`@line()`](/indie/Library-reference/package-indie-plot#decor_line) [`@level()`](/indie/Library-reference/package-indie#decor_level) [`@fill()`](/indie/Library-reference/package-indie-plot#decor_fill)
***
### `source`
*enum*
Enum-like class with constants for various price sources (it is used in `@indie.param.source`).
Built-in source kind constant which corresponds to `Context`'s series field and is used to initialize source input parameter.
Built-in source kind constant which corresponds to `Context`'s series field and is used to initialize source input parameter.
Built-in source kind constant which corresponds to `Context`'s series field and is used to initialize source input parameter.
Built-in source kind constant which corresponds to `Context`'s series field and is used to initialize source input parameter.
Built-in source kind constant which corresponds to `Context`'s series field and is used to initialize source input parameter.
Built-in source kind constant which corresponds to `Context`'s series field and is used to initialize source input parameter.
Built-in source kind constant which corresponds to `Context`'s series field and is used to initialize source input parameter.
Built-in source kind constant which corresponds to `Context`'s series field and is used to initialize source input parameter.
See also: [`@param.source()`](/indie/Library-reference/package-indie#decor_param_source)
***
### `time_frame_unit`
*enum*
Enum-like class with constants for time frame units.
Built-in constants that represent time frame units.
Built-in constants that represent time frame units.
Built-in constants that represent time frame units.
Built-in constants that represent time frame units.
Built-in constants that represent time frame units.
See also: [`TimeFrame`](/indie/Library-reference/package-indie#class_TimeFrame)
***
# Package indie.algorithms
Source: https://takeprofit.com/docs/indie/Library-reference/package-indie-algorithms
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Algorithms package of Indie language.
***
## Types
### `Adx`
*type*
Average directional index algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Minus Directional Indicator*, *Average Directional Index* and *Plus Directional Indicator*.
Number of bars to calculate smoothing.
Number of bars to calculate directional indicator.
Returns series of *Minus Directional Indicator*, *Average Directional Index* and *Plus Directional Indicator*.
Number of bars to calculate smoothing.
Number of bars to calculate directional indicator.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Adx
@indicator('Example')
def Main(self):
minus_di, adx, plus_di = Adx.new(adx_len=9, di_len=12)
return minus_di[0], adx[0], plus_di[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Change, Rma, Tr, FixNan
from indie.math import divide
@algorithm
def Adx(self, adx_len: int, di_len: int) -> tuple[SeriesF, SeriesF, SeriesF]:
'''Average Directional Index'''
up = Change.new(self.ctx.high)[0]
down = -Change.new(self.ctx.low)[0]
plus_dm = MutSeriesF.new(0 if up <= down or up <= 0 else up)
minus_dm = MutSeriesF.new(0 if down <= up or down <= 0 else down)
truerange = Rma.new(Tr.new(), di_len)
plus = MutSeriesF.new(100 * divide(Rma.new(plus_dm, di_len)[0], truerange[0]))
minus = MutSeriesF.new(100 * divide(Rma.new(minus_dm, di_len)[0], truerange[0]))
plus[0] = FixNan.new(plus)[0]
minus[0] = FixNan.new(minus)[0]
sum = plus[0] + minus[0]
res = 100 * Rma.new(MutSeriesF.new(abs(plus[0] - minus[0]) / (sum if sum != 0 else 1)), adx_len)[0]
return minus, MutSeriesF.new(res), plus
```
***
### `Atr`
*type*
Average true range algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Average True Range* values calculated for the `length` bars period using moving average specified by `ma_algorithm` argument.
Number of bars in calculation taken into account.
Moving average algorithm name, should be one of `'EMA'`, `'SMA'`, `'SMMA (RMA)'`, `'RMA'`, `'VWMA'` or `'WMA'`.
Returns series of *Average True Range* values calculated for the `length` bars period using moving average specified by `ma_algorithm` argument.
Number of bars in calculation taken into account.
Moving average algorithm name, should be one of `'EMA'`, `'SMA'`, `'SMMA (RMA)'`, `'RMA'`, `'VWMA'` or `'WMA'`.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Atr
@indicator('Example')
def Main(self):
atr = Atr.new(length=12, ma_algorithm='SMA')
return atr[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF
from indie.algorithms import Tr, Ma
@algorithm
def Atr(self, length: int, ma_algorithm: str = 'RMA') -> SeriesF:
'''Average True Range'''
return Ma.new(Tr.new(True), length, ma_algorithm)
```
***
### `Bb`
*type*
Bollinger bands algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns middle, upper and lower series of *Bollinger Bands* calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Multiplier for standard deviation.
Returns middle, upper and lower series of *Bollinger Bands* calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Multiplier for standard deviation.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Bb
@indicator('Example', overlay_main_pane=True)
def Main(self):
lower, middle, upper = Bb.new(self.close, length=20, mult=2.0)
return lower[0], middle[0], upper[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma, StdDev
@algorithm
def Bb(self, src: SeriesF, length: int, mult: float) -> tuple[SeriesF, SeriesF, SeriesF]:
'''Bollinger Bands'''
middle = Sma.new(src, length)[0]
dev = mult * StdDev.new(src, length)[0]
lower = middle - dev
upper = middle + dev
return MutSeriesF.new(lower), MutSeriesF.new(middle), MutSeriesF.new(upper)
```
***
### `Cci`
*type*
Commodity channel index algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Commodity Channel Index* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Commodity Channel Index* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Cci
@indicator('Example')
def Main(self):
cci = Cci.new(self.close, length=20)
return cci[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma, Dev
from indie.math import divide
@algorithm
def Cci(self, src: SeriesF, length: int) -> SeriesF:
'''Commodity Channel Index'''
ma = Sma.new(src, length)[0]
dv = Dev.new(src, length)[0]
res = divide(src[0] - ma, 0.015 * dv)
return MutSeriesF.new(res)
```
***
### `Change`
*type*
Algorithm to calculate change of a series of values. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns the difference between current `src` value and its value `length` bars ago.
Series data to perform the calculation.
Number of bars ago to compare the current value.
Returns the difference between current `src` value and its value `length` bars ago.
Series data to perform the calculation.
Number of bars ago to compare the current value.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Change
@indicator('Example')
def Main(self):
ch = Change.new(self.close)
return ch[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def Change(self, src: SeriesF, length: int = 1) -> SeriesF:
return MutSeriesF.new(src[0] - src[length])
```
***
### `Corr`
*type*
Correlation coefficient algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Correlation Coefficient* values calculated from `x` and `y` series for the `length` bars period.
First series to calculate correlation with.
Second series to calculate correlation with.
Number of bars in calculation taken into account.
Returns series of *Correlation Coefficient* values calculated from `x` and `y` series for the `length` bars period.
First series to calculate correlation with.
Second series to calculate correlation with.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Corr
@indicator('Example')
def Main(self):
corr = Corr.new(self.close, self.open, length=14)
return corr[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma, StdDev
from indie.math import divide
@algorithm
def Corr(self, x: SeriesF, y: SeriesF, length: int) -> SeriesF:
# NOTE: `cov` could be calculated as `E(x*y) - E(x)*E(y)`,
# but that may cause precision issues with floating-point arithmetic
e_x = Sma.new(x, length)[0]
e_y = Sma.new(y, length)[0]
cov = 0.0
for i in range(length):
cov += (x[i] - e_x) * (y[i] - e_y)
cov /= length
std_devs = StdDev.new(x, length)[0] * StdDev.new(y, length)[0]
corr = divide(cov, std_devs, 0.0)
return MutSeriesF.new(corr)
```
***
### `CumSum`
*type*
Cumulative sum algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of cumulative sum of `src` values.
Series data to perform the calculation.
Returns series of cumulative sum of `src` values.
Series data to perform the calculation.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import CumSum
@indicator('Example')
def Main(self):
cs = CumSum.new(self.close)
return cs[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def CumSum(self, src: SeriesF) -> SeriesF:
res = MutSeriesF.new(init=0)
res[0] += src[0]
return res
```
***
### `Dev`
*type*
Mean absolute deviation algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Mean Absolute Deviation* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Mean Absolute Deviation* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Dev
@indicator('Example')
def Main(self):
dev = Dev.new(self.close, length=12)
return dev[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma
@algorithm
def Dev(self, src: SeriesF, length: int) -> SeriesF:
'''Mean Absolute Deviation'''
mean = Sma.new(src, length)[0]
sum = 0.0
for i in range(length):
sum += abs(src[i] - mean)
return MutSeriesF.new(sum / length)
```
***
### `Donchian`
*type*
Donchian channels algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Middle Channel* of *Donchian Channels* calculated for the `length` bars period.
Number of bars in calculation taken into account.
Returns series of *Middle Channel* of *Donchian Channels* calculated for the `length` bars period.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Donchian
@indicator('DC', overlay_main_pane=True)
def Main(self):
d = Donchian.new(length=20)
return d[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, MutSeriesF, SeriesF
from indie.algorithms import Lowest, Highest
@algorithm
def Donchian(self, length: int) -> SeriesF:
lowest = Lowest.new(self.ctx.low, length)[0]
highest = Highest.new(self.ctx.high, length)[0]
return MutSeriesF.new((lowest + highest) / 2)
```
***
### `Ema`
*type*
Exponential moving average algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Exponential Moving Average* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Exponential Moving Average* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Ema
@indicator('Example', overlay_main_pane=True)
def Main(self):
ema = Ema.new(self.close, length=9)
return ema[0]
```
```py Source code
# indie:lang_version = 5
from math import isnan, nan
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma
@algorithm
def Ema(self, src: SeriesF, length: int) -> SeriesF:
'''Exponential Moving Average'''
alpha = 2 / (length + 1)
s = MutSeriesF.new(init=0)
res_sma = Sma.new(src, length)[0]
result = 0.0
if isnan(src[0]):
s[0] = nan
result = res_sma
elif isnan(s[1]):
s[0] = res_sma
result = s[0]
else:
s[0] = alpha * src[0] + (1 - alpha) * s[1]
result = s[0]
return MutSeriesF.new(result)
```
***
### `FixNan`
*type*
Algorithm that replaces all `math.nan` values with the most recent corresponding non-nan values in a series. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series created from `src` by replacing `math.nan` values with previous nearest non-`nan` value.
Series data to perform the calculation.
Returns series created from `src` by replacing `math.nan` values with previous nearest non-`nan` value.
Series data to perform the calculation.
```py Example
# indie:lang_version = 5
import math
from indie import indicator, MutSeriesF
from indie.algorithms import FixNan
@indicator('Example', overlay_main_pane=True)
def Main(self):
# Variable `s` is just an example of a series with `nan` values:
s = MutSeriesF.new(math.nan)
if self.close[0] > self.open[0]:
s[0] = self.close[0]
# `FixNan` replaces every `nan` value in `s` with the closest non-`nan` value on the left of it:
s2 = FixNan.new(s)
return s2[0]
```
```py Source code
# indie:lang_version = 5
from math import isnan
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def FixNan(self, src: SeriesF) -> SeriesF:
res = MutSeriesF.new(init=src[0])
if not isnan(src[0]):
res[0] = src[0]
return res
```
See also: [`NanToZero`](/indie/Library-reference/package-indie-algorithms#class_NanToZero)
***
### `Highest`
*type*
Algorithm that returns the maximum value over a given period. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns maximum value of given `src` series over a period of `length` bars.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns maximum value of given `src` series over a period of `length` bars.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Highest
@indicator('My Indie 1', overlay_main_pane=True)
def Main(self):
h = Highest.new(self.high, length=12)
return h[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def Highest(self, src: SeriesF, length: int) -> SeriesF:
src.request_size(length)
result = src[0]
for i in range(1, length):
result = max(src[i], result)
return MutSeriesF.new(result)
```
See also: [`SinceHighest`](/indie/Library-reference/package-indie-algorithms#class_SinceHighest)
***
### `LinReg`
*type*
Linear regression algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Linear Regression Curve* values calculated on `src` series for the `length` bars period (with possible offset `offset`).
Series data to perform the calculation.
Number of bars in calculation taken into account.
Offset of the argument to calculate *LinReg*.
Returns series of *Linear Regression Curve* values calculated on `src` series for the `length` bars period (with possible offset `offset`).
Series data to perform the calculation.
Number of bars in calculation taken into account.
Offset of the argument to calculate *LinReg*.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import LinReg
@indicator('Example')
def Main(self):
lr = LinReg.new(self.close, length=14, offset=0)
return lr[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma, StdDev, Corr
from indie.math import divide
@algorithm
def LinReg(self, y: SeriesF, length: int, offset: int = 0) -> SeriesF:
x = MutSeriesF.new(self.ctx.bar_index)
e_x = Sma.new(x, length)[0]
e_y = Sma.new(y, length)[0]
dev_x = StdDev.new(x, length)[0]
dev_y = StdDev.new(y, length)[0]
corr = Corr.new(x, y, length)[0]
slope = corr * divide(dev_y, dev_x)
inter = e_y - slope * e_x
reg = (x[0] - offset) * slope + inter
return MutSeriesF.new(reg)
```
***
### `Lowest`
*type*
Algorithm that returns the minimum value over a given period. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns minimum value of given `src` series over a period of `length` bars.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns minimum value of given `src` series over a period of `length` bars.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Lowest
@indicator('My Indie 1', overlay_main_pane=True)
def Main(self):
l = Lowest.new(self.low, length=12)
return l[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def Lowest(self, src: SeriesF, length: int) -> SeriesF:
src.request_size(length)
result = src[0]
for i in range(1, length):
result = min(src[i], result)
return MutSeriesF.new(result)
```
See also: [`SinceLowest`](/indie/Library-reference/package-indie-algorithms#class_SinceLowest)
***
### `Ma`
*type*
Moving average algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns a moving average of `src` specified by `algorithm` argument.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Moving average algorithm name, should be one of `'EMA'`, `'SMA'`, `'SMMA (RMA)'`, `'RMA'`, `'VWMA'` or `'WMA'`.
Returns a moving average of `src` specified by `algorithm` argument.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Moving average algorithm name, should be one of `'EMA'`, `'SMA'`, `'SMMA (RMA)'`, `'RMA'`, `'VWMA'` or `'WMA'`.
```py Example
# indie:lang_version = 5
from indie.algorithms import Ma
@indicator('Example', overlay_main_pane=True)
def Main(self):
ma = Ma.new(self.close, length=12, algorithm='SMA')
return ma[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, Optional, IndieError
from indie.algorithms import Ema, Sma, Rma, Vwma, Wma
@algorithm
def Ma(self, src: SeriesF, length: int, algorithm: str) -> SeriesF:
'''Moving Average'''
result: Optional[SeriesF]
if algorithm == 'EMA':
result = Ema.new(src, length)
elif algorithm == 'SMA':
result = Sma.new(src, length)
elif algorithm == 'SMMA (RMA)' or algorithm == 'RMA':
result = Rma.new(src, length)
elif algorithm == 'VWMA':
result = Vwma.new(src, length)
elif algorithm == 'WMA':
result = Wma.new(src, length)
else:
raise IndieError("moving average algorithm should be one of 'EMA', 'SMA', "
"'SMMA (RMA)', 'RMA', 'VWMA' or 'WMA' but it is " + algorithm)
return result.value()
```
***
### `Macd`
*type*
Moving average convergence/divergence algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Moving Average Convergence/Divergence*, *Signal Line* and *Histogram Line* values calculated from series of `src` for `fast_len`, `slow_len` and `sig_len` bars periods using moving averages specified by `ma_source` and `ma_signal` argument.
Series data to perform the calculation.
Fast length.
Slow length.
Signal length.
Moving average algorithm name, should be one of `'EMA'` or `'SMA'`.
Moving average algorithm name, should be one of `'EMA'` or `'SMA'`.
Returns series of *Moving Average Convergence/Divergence*, *Signal Line* and *Histogram Line* values calculated from series of `src` for `fast_len`, `slow_len` and `sig_len` bars periods using moving averages specified by `ma_source` and `ma_signal` argument.
Series data to perform the calculation.
Fast length.
Slow length.
Signal length.
Moving average algorithm name, should be one of `'EMA'` or `'SMA'`.
Moving average algorithm name, should be one of `'EMA'` or `'SMA'`.
```py Example
# indie:lang_version = 5
from indie.algorithms import Macd
@indicator('Example', overlay_main_pane=True)
def Main(self):
macd = Macd.new(self.close, fast_length=12, slow_length=26, sig_length=9, ma_source='EMA', ma_signal='EMA')
return macd[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Ma
@algorithm
def Macd(self, src: SeriesF, fast_len: int, slow_len: int, sig_len: int,
ma_source: str = 'EMA', ma_signal: str = 'EMA') -> tuple[SeriesF, SeriesF, SeriesF]:
'''Moving Average Convergence Divergence'''
fast_ma = Ma.new(src, fast_len, ma_source)
slow_ma = Ma.new(src, slow_len, ma_source)
macd = MutSeriesF.new(fast_ma[0] - slow_ma[0])
signal = Ma.new(macd, sig_len, ma_signal)
hist = MutSeriesF.new(macd[0] - signal[0])
return macd, signal, hist
```
***
### `Median`
*type*
Moving median algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Moving Median* values calculated from series of `src` for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Moving Median* values calculated from series of `src` for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Median
@indicator('Example', overlay_main_pane=True)
def Main(self):
m = Median.new(self.close, length=10)
return m[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from statistics import median as stats_median
# TODO: Use quickselect median find algorithm, see more https://rcoh.me/posts/linear-time-median-finding/
@algorithm
def Median(self, src: SeriesF, length: int) -> SeriesF:
prices: list[float] = [] # TODO: Create list of size=length only once and clear+refill it
for i in range(length):
prices.append(src[i])
res = stats_median(prices) # type: ignore
return MutSeriesF.new(res)
```
***
### `Mfi`
*type*
Money flow index algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Money Flow Index* values calculated from series of `src` for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Money Flow Index* values calculated from series of `src` for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie.algorithms import Mfi
@indicator('Example', overlay_main_pane=True)
def Main(self):
mfi = Mfi.new(self.hlc3, length=14)
return mfi[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, MutSeriesF, SeriesF
from indie.math import divide
@algorithm
def Mfv(self) -> SeriesF:
'''Money Flow Volume'''
h = self.ctx.high[0]
l = self.ctx.low[0]
c = self.ctx.close[0]
v = self.ctx.volume[0]
res = v * divide((c - l) - (h - c), (h - l), 0.0)
return MutSeriesF.new(res)
```
***
### `Mfv`
*type*
Money flow volume algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Money Flow Volume*.
Returns series of *Money Flow Volume*.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Mfv
@indicator('Example')
def Main(self):
mfv = Mfv.new()
return mfv[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, MutSeriesF, SeriesF
from indie.math import divide
@algorithm
def Mfv(self) -> SeriesF:
'''Money Flow Volume'''
h = self.ctx.high[0]
l = self.ctx.low[0]
c = self.ctx.close[0]
v = self.ctx.volume[0]
res = v * divide((c - l) - (h - c), (h - l), 0.0)
return MutSeriesF.new(res)
```
***
### `NanToZero`
*type*
Algorithm that replaces all `math.nan` values with zeros in a series. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series created from `src` by replacing `math.nan` values with zeros.
Series data to perform the calculation.
Returns series created from `src` by replacing `math.nan` values with zeros.
Series data to perform the calculation.
```py Example
# indie:lang_version = 5
import math
from indie import indicator, MutSeriesF
from indie.algorithms import NanToZero
@indicator('Example')
def Main(self):
# Variable `s` is just an example of a series with `nan` values:
s = MutSeriesF.new(math.nan)
if self.close[0] > self.open[0]:
s[0] = 0 if math.isnan(s[1]) else s[1] + 1
# `NanToZero` replaces every `nan` value in `s` with zero
s2 = NanToZero.new(s)
return s2[0]
```
```py Source code
# indie:lang_version = 5
from math import isnan
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def NanToZero(self, src: SeriesF) -> SeriesF:
res = 0 if isnan(src[0]) else src[0]
return MutSeriesF.new(res)
```
See also: [`FixNan`](/indie/Library-reference/package-indie-algorithms#class_FixNan)
***
### `NetVolume`
*type*
Net volume algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Net Volume* values calculated on `src` series.
Series data to perform the calculation.
Returns series of *Net Volume* values calculated on `src` series.
Series data to perform the calculation.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import NetVolume
@indicator('Example')
def Main(self):
nv = NetVolume.new(self.close)
return nv[0]
```
```py Source code
# indie:lang_version = 5
from math import nan
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Change
@algorithm
def NetVolume(self, src: SeriesF) -> SeriesF:
der = Change.new(src)[0]
nv = MutSeriesF.new(init=nan)
if der > 0:
nv[0] = self.ctx.volume[0]
elif der < 0:
nv[0] = -self.ctx.volume[0]
elif der == 0:
nv[0] = 0
return nv
```
***
### `PercentRank`
*type*
Percent rank algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Percent Rank* (number of previous values that are less or equal to the current value) calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Percent Rank* (number of previous values that are less or equal to the current value) calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import PercentRank
@indicator('Example')
def Main(self):
pr = PercentRank.new(self.close, length=12)
return pr[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def PercentRank(self, src: SeriesF, length: int) -> SeriesF:
num_leq = 0
for idx in range(1, length + 1):
if src[idx] <= src[0]:
num_leq += 1
return MutSeriesF.new(100.0 * num_leq / length)
```
***
### `Rma`
*type*
RMA algorithm is a moving average algorithm that is used to calculate RSI. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns a *Moving Average* that is used in calculations of `Rsi`.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns a *Moving Average* that is used in calculations of `Rsi`.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Rma
@indicator('My Indie 1', overlay_main_pane=True)
def Main(self):
rma = Rma.new(self.close, length=12)
return rma[0]
```
```py Source code
# indie:lang_version = 5
from math import isnan
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma
@algorithm
def Rma(self, src: SeriesF, length: int) -> SeriesF:
'''RSI Moving Average'''
result = MutSeriesF.new(init=0)
if isnan(result[1]):
result[0] = Sma.new(src, length)[0]
else:
result[0] = (src[0] + (length - 1) * result[1]) / length
return result
```
***
### `Roc`
*type*
Rate of change algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Rate Of Change* (percentage of change between the current value and value `length` bars ago) calculated on `src` series.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Rate Of Change* (percentage of change between the current value and value `length` bars ago) calculated on `src` series.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Roc
@indicator('Example')
def Main(self):
roc = Roc.new(self.close, length=9)
return roc[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Change
from indie.math import divide
@algorithm
def Roc(self, src: SeriesF, length: int) -> SeriesF:
'''Rate Of Change'''
res = 100 * divide(Change.new(src, length)[0], src[length])
return MutSeriesF.new(res)
```
***
### `Rsi`
*type*
Relative strength index algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Relative Strength Index* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Relative Strength Index* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Rsi
@indicator('Example')
def Main(self):
rsi = Rsi.new(self.close, length=12)
return rsi[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import NanToZero, Change, Rma
from indie.math import divide
@algorithm
def Rsi(self, src: SeriesF, length: int) -> SeriesF:
'''Relative Strength Index'''
u = max(NanToZero.new(Change.new(src))[0], 0) # upward change
rma_u = Rma.new(MutSeriesF.new(u), length)[0]
d = max(-NanToZero.new(Change.new(src))[0], 0) # downward change
rma_d = Rma.new(MutSeriesF.new(d), length)[0]
res = 100 * divide(rma_u, rma_u + rma_d, 1.0)
return MutSeriesF.new(res)
```
***
### `Sar`
*type*
Parabolic stop and reverse algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Parabolic Stop And Reverse* values.
Initial value for acceleration.
Increment value for acceleration.
Maximum value for acceleration.
Returns series of *Parabolic Stop And Reverse* values.
Initial value for acceleration.
Increment value for acceleration.
Maximum value for acceleration.
```py Example
# indie:lang_version = 5
from indie.algorithms import Sar
@indicator('Example', overlay_main_pane=True)
def Main(self):
sar = Sar.new(start=0.02, increment=0.02, maximum=0.2)
return sar[0]
```
```py Source code
# indie:lang_version = 5
from math import nan
from indie import algorithm, SeriesF, Var, MutSeriesF
@algorithm
def Sar(self, start: float, increment: float, maximum: float) -> SeriesF:
result = Var[float].new(init=nan)
max_min = Var[float].new(init=nan)
acceleration = Var[float].new(init=nan)
is_below = Var[bool].new(init=False)
is_first_trend_bar = False
if self.ctx.bar_index == 1:
if self.ctx.close[0] > self.ctx.close[1]:
is_below.set(True)
max_min.set(self.ctx.high[0])
result.set(self.ctx.low[1])
else:
is_below.set(False)
max_min.set(self.ctx.low[0])
result.set(self.ctx.high[1])
is_first_trend_bar = True
acceleration.set(start)
result.set(result.get() + acceleration.get() * (max_min.get() - result.get()))
if is_below.get():
if result.get() > self.ctx.low[0]:
is_first_trend_bar = True
is_below.set(False)
result.set(max(self.ctx.high[0], max_min.get()))
max_min.set(self.ctx.low[0])
acceleration.set(start)
else:
if result.get() < self.ctx.high[0]:
is_first_trend_bar = True
is_below.set(True)
result.set(min(self.ctx.low[0], max_min.get()))
max_min.set(self.ctx.high[0])
acceleration.set(start)
if not is_first_trend_bar:
if is_below.get():
if self.ctx.high[0] > max_min.get():
max_min.set(self.ctx.high[0])
acceleration.set(min(acceleration.get() + increment, maximum))
else:
if self.ctx.low[0] < max_min.get():
max_min.set(self.ctx.low[0])
acceleration.set(min(acceleration.get() + increment, maximum))
if is_below.get():
result.set(min(result.get(), self.ctx.low[1]))
if self.ctx.bar_index > 1:
result.set(min(result.get(), self.ctx.low[2]))
else:
result.set(max(result.get(), self.ctx.high[1]))
if self.ctx.bar_index > 1:
result.set(max(result.get(), self.ctx.high[2]))
return MutSeriesF.new(result.get())
```
***
### `SinceHighest`
*type*
Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns the number of bars after the maximum price for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns the number of bars after the maximum price for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import SinceHighest
@indicator('Example')
def Main(self):
sh = SinceHighest.new(self.high, length=10)
return sh[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, Series, MutSeries
@algorithm
def SinceHighest(self, src: SeriesF, length: int) -> Series[int]:
offset = 0
for idx in range(length):
if src[idx] >= src[offset]:
offset = idx
return MutSeries[int].new(offset)
```
See also: [`Highest`](/indie/Library-reference/package-indie-algorithms#class_Highest)
***
### `SinceLowest`
*type*
Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns the number of bars after the minimum price for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns the number of bars after the minimum price for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import SinceLowest
@indicator('Example')
def Main(self):
sl = SinceLowest.new(self.high, length=10)
return sl[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, Series, MutSeries
@algorithm
def SinceLowest(self, src: SeriesF, length: int) -> Series[int]:
offset = 0
for idx in range(length):
if src[idx] <= src[offset]:
offset = idx
return MutSeries[int].new(offset)
```
See also: [`Lowest`](/indie/Library-reference/package-indie-algorithms#class_Lowest)
***
### `SinceTrue`
*type*
Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns an index of the last `True` in `condition` series; if no such `True` is found, returns `-1`.
Bool series to find `True`.
Returns an index of the last `True` in `condition` series; if no such `True` is found, returns `-1`.
Bool series to find `True`.
```py Example
# indie:lang_version = 5
from indie import indicator, MutSeries
from indie.algorithms import SinceTrue
@indicator('Example')
def Main(self):
cond = MutSeries[bool].new(self.close[0] > self.open[0])
index = SinceTrue.new(cond)
return index
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, Series, MutSeries
@algorithm
def SinceTrue(self, condition: Series[bool]) -> Series[int]:
result = MutSeries[int].new(init=-1)
if condition[0]:
result[0] = 0
elif result[0] != -1:
result[0] += 1
return result
```
***
### `Sma`
*type*
Simple moving average algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Simple Moving Average* values calculated from series of `src` for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Simple Moving Average* values calculated from series of `src` for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Sma
@indicator('Example')
def Main(self):
sma = Sma.new(self.close, length=12)
return sma[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sum
@algorithm
def Sma(self, src: SeriesF, length: int) -> SeriesF:
'''Simple Moving Average'''
s = Sum.new(src, length)
return MutSeriesF.new(s[0] / length)
```
***
### `StdDev`
*type*
Standard deviation algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Standard Deviation* values calculated from series of `src` for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Standard Deviation* values calculated from series of `src` for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import StdDev
@indicator('Example')
def Main(self):
sd = StdDev.new(self.close, length=12)
return sd[0]
```
```py Source code
# indie:lang_version = 5
from math import sqrt
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma
@algorithm
def StdDev(self, src: SeriesF, length: int) -> SeriesF:
# NOTE: `var_` could be calculated as `E(src^2) - E(src)^2`,
# but that may cause precision issues with floating-point arithmetic
avg = Sma.new(src, length)[0]
var_ = 0.0
for i in range(length):
dev = src[i] - avg
var_ += dev * dev
var_ /= length
return MutSeriesF.new(sqrt(var_))
```
***
### `Stoch`
*type*
Stochastic algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Stochastic* on `src` series with `high` and `low` highs and lows of the source over a period of `length` bars.
Series data to perform the calculation.
Series of low values.
Series of high values.
Number of bars in calculation taken into account.
Returns series of *Stochastic* on `src` series with `high` and `low` highs and lows of the source over a period of `length` bars.
Series data to perform the calculation.
Series of low values.
Series of high values.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Stoch
@indicator('Example')
def Main(self):
s = Stoch.new(self.close, self.low, self.high, length=14)
return s[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Lowest, Highest
from indie.math import divide
@algorithm
def Stoch(self, src: SeriesF, low: SeriesF, high: SeriesF, length: int) -> SeriesF:
lowest_low = Lowest.new(low, length)[0]
highest_high = Highest.new(high, length)[0]
res = 100 * divide(src[0] - lowest_low, highest_high - lowest_low, 1.0)
return MutSeriesF.new(res)
```
***
### `Sum`
*type*
Sliding sum algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Sliding Sum* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Sliding Sum* values calculated on `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Sum
@indicator('Example')
def Main(self):
s = Sum.new(self.close, length=10)
return s[0]
```
```py Source code
# indie:lang_version = 5
from math import isnan, nan
from indie import algorithm, SeriesF, MutSeriesF, Var
def nan_to_zero(val: float) -> float:
return 0 if isnan(val) else val
@algorithm
def Sum(self, src: SeriesF, length: int) -> SeriesF:
src.request_size(length + 1)
nan_count = Var[int].new(0)
sum = Var[float].new(0)
sum.set(sum.get() + nan_to_zero(src[0]))
result = 0.0
if isnan(src[0]):
nan_count.set(nan_count.get() + 1)
result = nan
else:
if len(src) - nan_count.get() > length:
sum.set(sum.get() - src[length])
if len(src) - nan_count.get() < length:
result = nan
else:
result = sum.get()
return MutSeriesF.new(result)
```
***
### `Supertrend`
*type*
Supertrend algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns a tuple of two *Supertrend* series: *Supertrend Line* and *Direction Of Trend*.
The multiplier by which the *ATR* will get multiplied.
Number of bars to calculate *ATR*.
Moving average algorithm name, should be one of `'EMA'`, `'SMA'`, `'SMMA (RMA)'`, `'RMA'`, `'VWMA'` or `'WMA'`.
Returns a tuple of two *Supertrend* series: *Supertrend Line* and *Direction Of Trend*.
The multiplier by which the *ATR* will get multiplied.
Number of bars to calculate *ATR*.
Moving average algorithm name, should be one of `'EMA'`, `'SMA'`, `'SMMA (RMA)'`, `'RMA'`, `'VWMA'` or `'WMA'`.
```py Example
# indie:lang_version = 5
from indie import indicator, color, plot
from indie.algorithms import Supertrend
@indicator('Example', overlay_main_pane=True)
def Main(self):
st, dir = Supertrend.new(factor=3.0, atr_period=10, ma_algorithm='SMA')
c = color.RED if dir[0] > 0 else color.GREEN
return plot.Line(st[0], color=c)
```
```py Source code
# indie:lang_version = 5
from math import isnan
from indie import algorithm, MutSeriesF, SeriesF
from indie.algorithms import Atr
def nan_to_val(maybe_nan: float, val: float) -> float:
return val if isnan(maybe_nan) else maybe_nan
@algorithm
def Supertrend(self, factor: float, atr_period: int, ma_algorithm: str) -> tuple[SeriesF, SeriesF]:
src = self.ctx.hl2
atr = Atr.new(atr_period, ma_algorithm)
upper_band = MutSeriesF.new(src[0] + factor * atr[0])
lower_band = MutSeriesF.new(src[0] - factor * atr[0])
prev_lower_band = nan_to_val(lower_band[1], 0)
prev_upper_band = nan_to_val(upper_band[1], 0)
lower_band[0] = lower_band[0] \
if lower_band[0] > prev_lower_band or self.ctx.close[1] < prev_lower_band \
else prev_lower_band
upper_band[0] = upper_band[0] \
if upper_band[0] < prev_upper_band or self.ctx.close[1] > prev_upper_band \
else prev_upper_band
direction: float
super_trend = MutSeriesF.new(init=0)
prev_super_trend = super_trend[1]
if isnan(atr[1]):
direction = 1.0
elif prev_super_trend == prev_upper_band:
direction = -1.0 if self.ctx.close[0] > upper_band[0] else 1.0
else:
direction = 1.0 if self.ctx.close[0] < lower_band[0] else -1.0
super_trend[0] = lower_band[0] if direction < 0 else upper_band[0]
return super_trend, MutSeriesF.new(direction)
```
***
### `Tr`
*type*
True range algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *True Range* values.
Flag that says how `NaN` close values of the previous day are handled.
Returns series of *True Range* values.
Flag that says how `NaN` close values of the previous day are handled.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Tr
@indicator('Example')
def Main(self):
tr = Tr.new()
return tr[0]
```
```py Source code
# indie:lang_version = 5
from math import nan, isnan
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def Tr(self, handle_na: bool = False) -> SeriesF:
'''True Range'''
res = nan if handle_na else self.ctx.high[0] - self.ctx.low[0]
if not isnan(self.ctx.close[1]):
res = max(
self.ctx.high[0] - self.ctx.low[0],
abs(self.ctx.high[0] - self.ctx.close[1]),
abs(self.ctx.low[0] - self.ctx.close[1]),
)
return MutSeriesF.new(res)
```
***
### `Tsi`
*type*
True strength index algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *True Strength Index* values.
Series data to perform the calculation.
Long length.
Short length.
Returns series of *True Strength Index* values.
Series data to perform the calculation.
Long length.
Short length.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Tsi
@indicator('Example')
def Main(self):
tsi = Tsi.new(self.close, long_len=21, short_len=12)
return tsi[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Ema, Change
from indie.math import divide
@algorithm
def DoubleSmooth(self, src: SeriesF, long_len: int, short_len: int) -> SeriesF:
return Ema.new(Ema.new(src, long_len), short_len)
@algorithm
def Tsi(self, src: SeriesF, long_len: int, short_len: int) -> SeriesF:
'''True Strength Index'''
pc = Change.new(src)
double_smoothed_pc = DoubleSmooth.new(pc, long_len, short_len)[0]
abs_pc = MutSeriesF.new(abs(pc[0]))
double_smoothed_abs_pc = DoubleSmooth.new(abs_pc, long_len, short_len)[0]
res = divide(double_smoothed_pc, double_smoothed_abs_pc)
return MutSeriesF.new(res)
```
***
### `Uo`
*type*
Ultimate oscillator algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Ultimate Oscillator* values calculated for `fast_len`, `middle_len` and `slow_len` bars periods.
Fast length.
Middle length.
Slow length.
Returns series of *Ultimate Oscillator* values calculated for `fast_len`, `middle_len` and `slow_len` bars periods.
Fast length.
Middle length.
Slow length.
```py Example
# indie:lang_version = 5
from indie.algorithms import Uo
@indicator('Example', overlay_main_pane=True)
def Main(self):
uo = Uo.new(fast_len=7, middle_len=14, slow_len=28)
return uo[0]
```
```py Source code
# indie:lang_version = 5
from math import nan
from indie import algorithm, SeriesF, Var, MutSeriesF
@algorithm
def Sar(self, start: float, increment: float, maximum: float) -> SeriesF:
result = Var[float].new(init=nan)
max_min = Var[float].new(init=nan)
acceleration = Var[float].new(init=nan)
is_below = Var[bool].new(init=False)
is_first_trend_bar = False
if self.ctx.bar_index == 1:
if self.ctx.close[0] > self.ctx.close[1]:
is_below.set(True)
max_min.set(self.ctx.high[0])
result.set(self.ctx.low[1])
else:
is_below.set(False)
max_min.set(self.ctx.low[0])
result.set(self.ctx.high[1])
is_first_trend_bar = True
acceleration.set(start)
result.set(result.get() + acceleration.get() * (max_min.get() - result.get()))
if is_below.get():
if result.get() > self.ctx.low[0]:
is_first_trend_bar = True
is_below.set(False)
result.set(max(self.ctx.high[0], max_min.get()))
max_min.set(self.ctx.low[0])
acceleration.set(start)
else:
if result.get() < self.ctx.high[0]:
is_first_trend_bar = True
is_below.set(True)
result.set(min(self.ctx.low[0], max_min.get()))
max_min.set(self.ctx.high[0])
acceleration.set(start)
if not is_first_trend_bar:
if is_below.get():
if self.ctx.high[0] > max_min.get():
max_min.set(self.ctx.high[0])
acceleration.set(min(acceleration.get() + increment, maximum))
else:
if self.ctx.low[0] < max_min.get():
max_min.set(self.ctx.low[0])
acceleration.set(min(acceleration.get() + increment, maximum))
if is_below.get():
result.set(min(result.get(), self.ctx.low[1]))
if self.ctx.bar_index > 1:
result.set(min(result.get(), self.ctx.low[2]))
else:
result.set(max(result.get(), self.ctx.high[1]))
if self.ctx.bar_index > 1:
result.set(max(result.get(), self.ctx.high[2]))
return MutSeriesF.new(result.get())
```
***
### `Vwap`
*type*
Volume weighted average price algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Volume Weighted Average Price* values with band of its standard deviation.
Series data to perform the calculation.
At what points in time do we need to reset the accumulated amounts. Valid values are: 'day', 'week', 'month', 'year'.
Multiplier for standard deviation.
Returns series of *Volume Weighted Average Price* values with band of its standard deviation.
Series data to perform the calculation.
At what points in time do we need to reset the accumulated amounts. Valid values are: 'day', 'week', 'month', 'year'.
Multiplier for standard deviation.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Vwap
@indicator('Example', overlay_main_pane=True)
def Main(self):
main_line, upper, lower = Vwap.new(self.close, anchor='Day', std_dev_mult=1.0)
return main_line[0], upper[0], lower[0]
```
```py Source code
# indie:lang_version = 5
from math import sqrt
from datetime import datetime
from indie import algorithm, SeriesF, MutSeriesF, Var
@algorithm
def Vwap(self, src: SeriesF, anchor: str, std_dev_mult: float) -> tuple[SeriesF, SeriesF, SeriesF]:
'''
Volume Weighted Average Price
anchor can be 'Session', 'Week', 'Month', 'Year'
'''
cum_weighted_price = Var[float].new(0)
cum_volume = Var[float].new(0)
vwap_sum = Var[float].new(0)
vwap_count = Var[int].new(0)
vwap_dev_squares = Var[float].new(0)
current_datetime = datetime.utcfromtimestamp(self.ctx.time[0])
prev_datetime = datetime.utcfromtimestamp(self.ctx.time.get(1, 0))
need_reset = False
if anchor == 'Session' and \
not self.ctx.trading_session.is_same_period(self.ctx.time[0], self.ctx.time.get(1, 0)):
need_reset = True
elif anchor == 'Week' and ((current_datetime.weekday() == 0 and prev_datetime.weekday() != 0) or
(current_datetime-prev_datetime).days >= 7):
need_reset = True
elif anchor == 'Month' and (current_datetime.month != prev_datetime.month or
(current_datetime-prev_datetime).days >= 31):
need_reset = True
elif anchor == 'Year' and current_datetime.year != prev_datetime.year:
need_reset = True
if need_reset:
cum_weighted_price.set(0)
cum_volume.set(0)
vwap_sum.set(0)
vwap_count.set(0)
vwap_dev_squares.set(0)
cum_weighted_price.set(cum_weighted_price.get() + src[0] * self.ctx.volume[0])
cum_volume.set(cum_volume.get() + self.ctx.volume[0])
vwap_value = cum_weighted_price.get() / cum_volume.get()
vwap_sum.set(vwap_sum.get() + vwap_value)
vwap_count.set(vwap_count.get() + 1)
vwap_avg = vwap_sum.get() / vwap_count.get()
vwap_dev_squares.set(vwap_dev_squares.get() + (vwap_value - vwap_avg) ** 2)
vwap_std_dev = sqrt(vwap_dev_squares.get() / vwap_count.get())
std_dev = std_dev_mult * vwap_std_dev
lower = MutSeriesF.new(vwap_value - std_dev)
upper = MutSeriesF.new(vwap_value + std_dev)
return MutSeriesF.new(vwap_value), upper, lower
```
***
### `Vwma`
*type*
Volume weighted moving average algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Volume Weighted Moving Average* values calculated for `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Volume Weighted Moving Average* values calculated for `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Vwma
@indicator('Example', overlay_main_pane=True)
def Main(self):
vwma = Vwma.new(self.close, length=12)
return vwma[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
from indie.algorithms import Sma
from indie.math import divide
@algorithm
def Vwma(self, src: SeriesF, length: int) -> SeriesF:
'''Volume Weighted Moving Average'''
src_vol = MutSeriesF.new(src[0] * self.ctx.volume[0])
sma_src_vol = Sma.new(src_vol, length)
sma_vol = Sma.new(self.ctx.volume, length)
res = divide(sma_src_vol[0], sma_vol[0])
return MutSeriesF.new(res)
```
***
### `Wma`
*type*
Weighted moving average algorithm. Read [here](/indie/Algorithms-for-series-processing#tl-dr-how-to-use-classes-from-indie-algorithms-package-in-my-indicator) about how to use it.
[`Algorithm`](/indie/Library-reference/package-indie#class_Algorithm)
Represents context of an instrument which is currently bound to this algorithm instance. An indicator has at least one instrument — the main instrument of a chart where the indicator was added to. Besides the main instrument an indicator may have several additional instruments, which is done with the help of `Context.calc_on` function.
Class constructor (initializer for the data type).
Context object.
Returns series of *Weighted Moving Average* values calculated for `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
Returns series of *Weighted Moving Average* values calculated for `src` series for the `length` bars period.
Series data to perform the calculation.
Number of bars in calculation taken into account.
```py Example
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Wma
@indicator('Example', overlay_main_pane=True)
def Main(self):
wma = Wma.new(self.close, length=12)
return wma[0]
```
```py Source code
# indie:lang_version = 5
from indie import algorithm, SeriesF, MutSeriesF
@algorithm
def Wma(self, src: SeriesF, length: int) -> SeriesF:
'''Weighted Moving Average'''
norm = 0.0
s = 0.0
for i in range(length):
weight = length - i
norm += weight
s += src[i] * weight
return MutSeriesF.new(s / norm)
```
***
# Package indie.color
Source: https://takeprofit.com/docs/indie/Library-reference/package-indie-color
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Package for builtin colors and `rgba` function.
See also: [`@line()`](/indie/Library-reference/package-indie-plot#decor_line) [`Line`](/indie/Library-reference/package-indie-plot#class_Line) [`Color`](/indie/Library-reference/package-indie#class_Color)
***
## Variables
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
Built-in color.
***
## Functions
### `rgba()`
*function*
Creates a `Color` object by its RGB components and alpha channel.
Red component of color.
Green component of color.
Blue component of color.
Alpha channel (component) of color which ranges from `0.0` (fully transparent) to `1.0` (fully opaque).
***
# Package indie.math
Source: https://takeprofit.com/docs/indie/Library-reference/package-indie-math
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Utility functions for simple calculations in Indie indicators.
***
## Functions
### `cross()`
*function*
Checks if two series just have crossed each other.
First series to make crossing check.
Second series to make crossing check.
Checks if two series just have crossed each other.
Series to make crossing check.
Constant level to make crossing check.
***
### `cross_over()`
*function*
Checks if the first series just have crossed over the second one.
First series to make crossing check.
Second series to make crossing check.
Checks if the first series just have crossed over the second one.
Series to make crossing check.
Constant level to make crossing check.
***
### `cross_under()`
*function*
Checks if the first series just have crossed under the second one.
First series to make crossing check.
Second series to make crossing check.
Checks if the first series just have crossed under the second one.
Series to make crossing check.
Constant level to make crossing check.
***
### `divide()`
*function*
Safely divides two numbers, returning a default value if the denominator is near zero.
Numerator.
Denominator.
Default value.
***
# Package indie.plot
Source: https://takeprofit.com/docs/indie/Library-reference/package-indie-plot
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Package for plotting series-like data.
***
## Decorators
### `@columns()`
*decorator*
Declares attributes of a columns plot of an indicator. Can be applied only to the `Main` entry point of the indicator. When applied, it must match with the result of the `Main` indicator entry point.
A unique identifier of plot, reserved for internal use.
Human readable title which is visible in the indicator's Settings panel.
Color of the plot.
Base level from which to start plot.
Relative width.
Determines the ways to display plot data.
```py Example
@plot.line()
@plot.columns(line_width=2)
@plot.columns(color=color.YELLOW)
# @plot.line() - for the fourth plot can be omitted
def Main(self):
return self.open[0], self.high[0], self.low[0], self.close[0]
```
See also: [`Columns`](/indie/Library-reference/package-indie-plot#class_Columns)
***
### `@fill()`
*decorator*
Declares attributes of a fill plot of an indicator. Can be applied only to the `Main` entry point of the indicator. When applied, it must match with the result of the `Main` indicator entry point.
Identifier of the first plot to which the fill is applied.
Identifier of the second plot to which the fill is applied.
A unique identifier of plot, reserved for internal use.
Human readable title which is visible in the indicator's Settings panel.
Color of the plot.
```py Example
@plot.line('plot1')
@plot.line('plot2')
@plot.fill('plot1', 'plot2')
def Main(self):
return self.open[0], self.high[0], plot.Fill()
```
See also: [`Fill`](/indie/Library-reference/package-indie-plot#class_Fill)
***
### `@histogram()`
*decorator*
Declares attributes of a histogram plot of an indicator. Can be applied only to the `Main` entry point of the indicator. When applied, it must match with the result of the `Main` indicator entry point.
A unique identifier of plot, reserved for internal use.
Human readable title which is visible in the indicator's Settings panel.
Color of the plot.
Width of the line.
Base level from which to start plot.
Determines the ways to display plot data.
```py Example
@plot.line()
@plot.histogram(line_width=2)
@plot.histogram(color=color.YELLOW)
# @plot.line() - for the fourth plot can be omitted
def Main(self):
return self.open[0], self.high[0], self.low[0], self.close[0]
```
See also: [`Histogram`](/indie/Library-reference/package-indie-plot#class_Histogram)
***
### `@line()`
*decorator*
Declares attributes of a line plot of an indicator. Can be applied only to the `Main` entry point of the indicator. It is optional, so may be omitted in some simple use cases and plot will be rendered using defaults. When applied, it must match with the result of the `Main` indicator entry point.
A unique identifier of plot which is used in cases when a `@plot.fill()` should be applied between some of the two plots of an indicator.
Human readable title which is visible in the indicator's Settings panel.
Color of the plot on a chart. This color can be overwritten if the plot is a multicolored one. Example of an indicator with a multicolored plot is *Awesome Oscillator (AO)*.
Style of the line. It is represented as enum value of type `line_style`.
Width of the line.
Whether the plot should be continuous when the indicator has `NaN` values.
Determines the ways to display plot data.
```py Example
@plot.line()
@plot.line(line_width=2)
@plot.line(color=color.YELLOW)
# @plot.line() - for the fourth plot can be omitted
def Main(self):
return self.open[0], self.high[0], self.low[0], self.close[0]
```
See also: [`Line`](/indie/Library-reference/package-indie-plot#class_Line)
***
### `@marker()`
*decorator*
Declares attributes of a marker plot of an indicator. Can be applied only to the `Main` entry point of the indicator. When applied, it must match with the result of the `Main` indicator entry point.
Human readable title which is visible in the indicator's Settings panel.
Color of the plot.
Default value for the text label of markers.
Determines how the plot data is rendered. It is represented as enum value of type `marker_style`.
Determines how the data and text are rendered.
Size of markers.
Determines the ways to display plot data.
```py Example
@plot.line()
@plot.marker(line_width=2)
@plot.marker(color=color.YELLOW)
# @plot.line() - for the fourth plot can be omitted
def Main(self):
return self.open[0], self.high[0], self.low[0], self.close[0]
```
See also: [`Marker`](/indie/Library-reference/package-indie-plot#class_Marker)
***
### `@steps()`
*decorator*
Declares attributes of a steps plot of an indicator. Can be applied only to the `Main` entry point of the indicator. When applied, it must match with the result of the `Main` indicator entry point.
A unique identifier of plot, reserved for internal use.
Human readable title which is visible in the indicator's Settings panel.
Color of the plot.
Width of the line.
Determines the ways to display plot data.
```py Example
@plot.line()
@plot.steps(line_width=2)
@plot.steps(color=color.YELLOW)
# @plot.line() - for the fourth plot can be omitted
def Main(self):
return self.open[0], self.high[0], self.low[0], self.close[0]
```
See also: [`Steps`](/indie/Library-reference/package-indie-plot#class_Steps)
***
## Types
### `Columns`
*type*
Class which objects represent an element of columns plot.
Value of the plot element.
Color of the plot element.
Offset of the plot element.
Class constructor (initializer for the data type).
Value of the plot element.
Color of the plot element.
Offset of the plot element.
See also: [`@columns()`](/indie/Library-reference/package-indie-plot#decor_columns)
***
### `ColumnsDisplayOptions`
*type*
Class with options that control how to display plot data on a chart.
Class constructor (initializer for the data type).
Whether or not to draw (by default) the plot on the pane.
Whether or not to show the value of the plot in the status line.
Whether or not to show the value label of the plot on the price axis.
***
### `Fill`
*type*
Class which objects represent an element of fill plot.
Color of the plot element.
Offset of the plot element.
Class constructor (initializer for the data type).
Color of the plot element.
Offset of the plot element.
See also: [`@fill()`](/indie/Library-reference/package-indie-plot#decor_fill)
***
### `Histogram`
*type*
Class which objects represent an element of histogram plot.
Value of the plot element.
Color of the plot element.
Offset of the plot element.
Class constructor (initializer for the data type).
Value of the plot element.
Color of the plot element.
Offset of the plot element.
See also: [`@histogram()`](/indie/Library-reference/package-indie-plot#decor_histogram)
***
### `HistogramDisplayOptions`
*type*
Class with options that control how to display plot data on a chart.
Class constructor (initializer for the data type).
Whether or not to draw (by default) the plot on the pane.
Whether or not to show the value of the plot in the status line.
Whether or not to show the value label of the plot on the price axis.
***
### `Line`
*type*
Class which objects represent an element of line plot.
Value of the plot element.
Color of the plot element.
Offset of the plot element.
Class constructor (initializer for the data type).
Value of the plot element.
Color of the plot element.
Offset of the plot element.
See also: [`@line()`](/indie/Library-reference/package-indie-plot#decor_line)
***
### `LineDisplayOptions`
*type*
Class with options that control how to display plot data on a chart.
Class constructor (initializer for the data type).
Whether or not to draw (by default) the plot on the pane.
Whether or not to show the value of the plot in the status line.
Whether or not to show the value label of the plot on the price axis.
***
### `Marker`
*type*
Class which objects represent an element of marker plot.
Value of the plot element.
Color of the plot element.
Marker text.
Offset of the plot element.
Class constructor (initializer for the data type).
Value of the plot element.
Color of the plot element.
Marker text.
Offset of the plot element.
See also: [`@marker()`](/indie/Library-reference/package-indie-plot#decor_marker)
***
### `MarkerDisplayOptions`
*type*
Class with options that control how to display plot data on a chart.
Class constructor (initializer for the data type).
Whether or not to draw (by default) the plot on the pane.
Whether or not to show the value of the plot in the status line.
Whether or not to show the value label of the plot on the price axis.
***
### `Steps`
*type*
Class which objects represent an element of steps plot.
Value of the plot element.
Color of the plot element.
Offset of the plot element.
Class constructor (initializer for the data type).
Value of the plot element.
Color of the plot element.
Offset of the plot element.
See also: [`@steps()`](/indie/Library-reference/package-indie-plot#decor_steps)
***
### `StepsDisplayOptions`
*type*
Class with options that control how to display plot data on a chart.
Class constructor (initializer for the data type).
Whether or not to draw (by default) the plot on the pane.
Whether or not to show the value of the plot in the status line.
Whether or not to show the value label of the plot on the price axis.
***
## Enums
### `marker_position`
*enum*
Enum-like class with constants of marker positions.
Built-in marker position constant that determines how the marker is rendered.
Built-in marker position constant that determines how the marker is rendered.
Built-in marker position constant that determines how the marker is rendered.
Built-in marker position constant that determines how the marker is rendered.
Built-in marker position constant that determines how the marker is rendered.
***
### `marker_style`
*enum*
Enum-like class with constants of marker styles.
Built-in marker style constant that determines how the marker is rendered.
Built-in marker style constant that determines how the marker is rendered.
Built-in marker style constant that determines how the marker is rendered.
Built-in marker style constant that determines how the marker is rendered.
***
# Package indie.schedule
Source: https://takeprofit.com/docs/indie/Library-reference/package-indie-schedule
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Schedule package that contains classes for working with schedules.
***
## Variables
List of `week_day`'s from week\_day.MONDAY to week\_day.SUNDAY
List of `week_day`'s from week\_day.SATURDAY to week\_day.SUNDAY
List of `week_day`'s from week\_day.MONDAY to week\_day.FRIDAY
***
## Types
### `Schedule`
*type*
Data type that manages a collection of scheduling rules, allowing for specific times and exceptions to be defined.
Class constructor (initializer for the data type).
List of ScheduleRule instances that define the active scheduling rules.
List of dates that are excluded from the schedule only once.
List of dates that are excluded from the schedule every year.
Timezone for schedule.
Checks if the rules list in Schedule is empty. Returns `True` if list of rules is empty; otherwise, returns `False`.
Checks whether a given timestamp falls within the defined schedule. Returns `True` if the timestamp falls within the schedule's active periods, otherwise returns `False`.
Timestamp to check in defined schedule.
Checks whether a given timestamp falls within the defined schedule. Returns `True` if the timestamp falls within the schedule's active periods, otherwise returns `False`.
Datetime to check in defined schedule.
Determines whether two timestamps fall within the same schedule period on the same day. Returns `True` if both timestamps fall within the same period of the schedule, even if they are in different calendar days. False if the timestamps belong to different periods within the schedule.
First timestamp to check.
Second timestamp to check.
This method checks if two timestamps, which may belong to different calendar days, are part of the same schedule period. It handles cases where a schedule spans across two consecutive days (e.g., a trading schedule that extends past midnight) and ensures both timestamps belong to the same logical period within the schedule.
See also: [`TradingSession`](/indie/Library-reference/package-indie#class_TradingSession) [`TradingSession`](/indie/Library-reference/package-indie#class_TradingSession)
***
### `ScheduleRule`
*type*
Data type to represent a rule for a schedule, specifying the start and end times, along with the weekdays when the rule is active.
Class constructor (initializer for the data type).
Start time of the rule.
End time of the rule.
List of weekdays when the rule is active.
```py Example
# this rule applies from 9:00 AM to 6:30 PM (6:30 is not included) on weekdays (Monday through Friday).
rule = ScheduleRule(start=time(hour=9), end=time(hour=18, minute=30), days=WORKDAYS)
# this overnight_rule applies from 8:15 PM to 7:30 AM on weekdays (Monday through Friday).
overnight_rule = ScheduleRule(start=time(hour=20, minute=15), end=time(hour=7, minute=30), days=WORKDAYS)
```
For rules that span overnight (e.g., from 10:00 PM to 6:00 AM), the end time should be on the day listed in days, while the start time is understood to be on the previous day. This allows the rule to cover activities that occur late in the evening and extend into the early hours of the next day.
See also: [`Schedule`](/indie/Library-reference/package-indie-schedule#class_Schedule) [`TradingSession`](/indie/Library-reference/package-indie#class_TradingSession)
***
## Enums
### `week_day`
*enum*
Enum-like class with constants for days of week.
Built-in constants that represent days of week.
Built-in constants that represent days of week.
Built-in constants that represent days of week.
Built-in constants that represent days of week.
Built-in constants that represent days of week.
Built-in constants that represent days of week.
Built-in constants that represent days of week.
***
# Package math
Source: https://takeprofit.com/docs/indie/Library-reference/package-math
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Math package.
See description in the [official Python docs](https://docs.python.org/3.10/library/math.html).
***
## Variables
Standard constant of Indie math package (similar to Python's).
Standard constant of Indie math package (similar to Python's).
Standard constant of Indie math package (similar to Python's).
***
## Functions
### `acos()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `asin()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `atan()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `ceil()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `cos()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `exp()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `exp2()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `floor()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `isclose()`
*function*
Standard function of Indie math package (similar to Python's).
First value to check for proximity.
Second value to check for proximity.
Relative tolerance for proximity check.
Absolute tolerance for proximity check.
***
### `isnan()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `log()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `log10()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `log2()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `pow()`
*function*
Standard function of Indie math package (similar to Python's).
Base value to calculate exponentiation.
Exponent (power) value to calculate exponentiation.
***
### `sin()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `sqrt()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
### `tan()`
*function*
Standard function of Indie math package (similar to Python's).
Number on which the function will be calculated.
***
# Package statistics
Source: https://takeprofit.com/docs/indie/Library-reference/package-statistics
export const Anchor = ({id}) => {
return ;
};
export const Field = ({id, name, type, required, defaultVal, children}) => {
return
{id &&
}
{name}
{type}
{required &&
required
}
{defaultVal &&
default:
{defaultVal}
}
{children}
;
};
Statistics package.
See description in the [official Python docs](https://docs.python.org/3.10/library/statistics.html).
***
## Functions
### `fmean()`
*function*
Standard statistics function.
List on which the function will be calculated.
***
### `mean()`
*function*
Standard statistics function.
List on which the function will be calculated.
Standard statistics function.
List on which the function will be calculated.
***
### `median()`
*function*
Standard statistics function.
List on which the function will be calculated.
***
# null
Source: https://takeprofit.com/docs/indie/Quick-start
To get you started quickly, let's write some indicators, starting with simple examples and gradually moving on to more
complex ones.
## Minimal indicator
Here is a minimal indicator for TakeProfit, which simply plots the 'close' price of the current chart instrument as a
solid line:
```py
# indie:lang_version = 5
from indie import indicator
@indicator('Example 1')
def Main(self):
return self.close[0]
```
Let us take a closer look to what is happening in this example. First of all, the *entry point* of every indicator
is the `Main` function (it must be named `Main` to keep all things in a 'standardized' way).
The `Main` function is a function that is called per every candle of a chart instrument from left to right and after
that it is continued to be called on every realtime update of the last (rightmost) candle. To sum up, it returns an
*indicator value* for every candle of the main instrument.
There is a `self` parameter in the `Main` function and it is an object of type
[`MainContext`](/indie/Library-reference/package-indie#class_MainContext). It represents the main instrument of the chart, for example it
gives access to OHLCV values of the instrument (e.g. [`self.close`](/indie/Library-reference/package-indie#obj_Context_close)). If you are
familiar with Python, then you probably know that `self` is a reference to the instance of the class that is currently
being used. It has the exact same meaning in Indie, though there are no classes in the code (yet). The `@indicator`
decorator is a syntactic sugar that turns `def Main` function into a `class Main`. Read more about this in
[How Indie's syntactic sugar works](/indie/How-Indies-syntactic-sugar-works) section.
[*Context*](/indie/Library-reference/package-indie#class_Context), another new term (represented by a `self` parameter of `Main` function) is a representation of a current instrument displayed on a candle chart, with all it's prices (open, high, low, close,
volume, etc.), some state and any other possible attributes it may have. In our example we take a series of close prices `self.close` and apply a square brackets operator to it, to get the last (most recent) value of that price:
`self.close[0]`. Zero offset always corresponds to the last value (value on the last candle). Offset `1` corresponds to the value of the previous candle and so on.
Our `Main` function is decorated with a required [`@indicator`](/indie/Library-reference/package-indie#decor_indicator) decorator with a
required `title` param (`title` is the first param of this decorator, but you may write it in a kwarg form:
`@indicator(title='Example 1')`). In general, decorators (things which names start with a `@` character) provide
*meta*-information about indicators to TakeProfit's runtime. Meta-information describes indicator in some way, we will
see a lot of this further.
Finally, please note, that we have to `import` symbols like `indicator`, because they are not a part of Indie's
built-in symbols. For now, the list of things that are allowed to be imported in the indicator code is very limited.
But as the platform grows, the library will be expanded accordingly.
After you type (or better copy-paste) the above code into the *Code Editor* (which is a widget and it should be added
to your workspace first as **More Widgets** -> **Indicators Code Editor**) click on the button **Add to Chart**.
As you can see, the indicator was added on a separate pane, below the main pane with candle chart.

## Overlay main pane
If we want to add our indicator as an overlay on candle chart, we may add `overlay_main_pane=True` param to the
`@indicator` decorator:
```py
# indie:lang_version = 5
from indie import indicator
@indicator('Example 2', overlay_main_pane=True)
def Main(self):
return self.close[0]
```

## Apply the SMA algorithm
TakeProfit has a library of standard algorithms, such as *Simple Moving Average* ([SMA](/indie/Library-reference/package-indie-algorithms#class_alg_Sma)), let us import and use it:
```py
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Sma
@indicator('Example 3', overlay_main_pane=True)
def Main(self):
s = Sma.new(self.close, 12)
return s[0]
```

There are two essential parts that make it work: 1) import of the `Sma` algorithm from package `indie.algorithms` and 2) invocation of `Sma.new` in the indicator's code: `Sma.new(self.close, 12)`. Algorithms that process series of prices
(like `self.close`) usually return series of numeric values (variable `s`). More about algorithms in [this chapter](/indie/Algorithms-for-series-processing).
Let us make our indicator more interesting and calculate two SMAs with different lengths:
```py
# indie:lang_version = 5
from indie import indicator
from indie.algorithms import Sma
@indicator('Example 4', overlay_main_pane=True)
def Main(self):
l = Sma.new(self.close, 42)
s = Sma.new(self.close, 12)
return l[0], s[0]
```
This indicator returns a *tuple* consisting of two values: `l[0]` and `s[0]`, that is why it plots two lines.

## Plot with different colors
There are two different ways to colorize indicator's plot lines. First one is to use one single color for the whole
plot. In such a way, colors are actually not involved in calculation over the candle prices, they are part of
indicator's meta-information. We use `@plot.line` decorator for such way of coloring:
```py
# indie:lang_version = 5
from indie import indicator, color, plot
from indie.algorithms import Sma
@indicator('Example 5', overlay_main_pane=True)
@plot.line(color=color.GRAY)
@plot.line(color=color.WHITE)
def Main(self):
l = Sma.new(self.close, 42)
s = Sma.new(self.close, 12)
return l[0], s[0]
```

What if we would like to make a multicolored plot line? We may want to calculate the color depending on
the candle prices data. If so, we would return from `Main` function not plain numbers, but `plot.Line` objects:
```py
# indie:lang_version = 5
from indie import indicator, color, plot
from indie.algorithms import Sma
@indicator('Example 6', overlay_main_pane=True)
@plot.line(color=color.GRAY)
def Main(self):
l = Sma.new(self.close, 42)
s = Sma.new(self.close, 12)
s_color = color.GREEN if s[0] > l[0] else color.RED
return l[0], plot.Line(s[0], color=s_color)
```

## Input parameters
It would be better not to hardcode the lengths of our two SMAs (literal constants `42` and `12`) but instead use named
parameters. Named parameters are very convenient because they can be modified in the indicator's **Settings** panel
without modifying the indicator's source code. For this purpose there are a whole set of decorators, starting with
`@param.` prefix, for example: `@param.int`, `@param.bool`, `@param.string` and so on. Let us incorporate them in our
example indicator:
```py
# indie:lang_version = 5
from indie import indicator, color, plot, param
from indie.algorithms import Sma
@indicator('Example 7', overlay_main_pane=True)
@param.int('long_length', default=42)
@param.int('short_length', default=12)
@plot.line(color=color.GRAY)
def Main(self, long_length, short_length):
l = Sma.new(self.close, long_length)
s = Sma.new(self.close, short_length)
s_color = color.GREEN if s[0] > l[0] else color.RED
return l[0], plot.Line(s[0], color=s_color)
```

More info about input parameters in [this](/indie/Input-parameters) chapter.
# null
Source: https://takeprofit.com/docs/indie/Request-additional-instruments
An indicator written in Indie is executed after it is added to a candle chart. The symbol and time frame of the
instrument of that chart is the main indicator instrument which is bound to the `Main` context of the indicator. It is
possible to request additional instrument data in indicator. For that purpose there are `@sec_context` decorator and
`indie.SecContext` class in combination with `Context.calc_on()` function.
## `@sec_context()` and `Context.calc_on()`
Decorator `@sec_context` is a syntactic sugar that can be applied to a function definition which is an equivalent of
writing a class inherited from `indie.SecContext` (more about the mechanics how this works can be found
[here](https://takeprofit.com/docs/indie/How-Indies-syntactic-sugar-works#functions-decorated-with-sec_context)). The
body of such a decorated function becomes an entry point for calculation when a data update is occurred on the
corresponding additional instrument. Function call of `Context.calc_on` creates a connection between the `Main` context
and the secondary one.
Here is an example of an indicator that requests one additional instrument:
```py
# indie:lang_version = 5
from indie import indicator, MainContext, sec_context, param
@sec_context
def SecMain(self):
return self.high[0], self.low[0]
@indicator('Minimal calc_on example', overlay_main_pane=True)
@param.time_frame('sec_time_frame', default='1D')
class Main(MainContext):
def __init__(self, sec_time_frame):
self._sec_high, self._sec_low = self.calc_on(SecMain, time_frame=sec_time_frame)
def calc(self):
return self._sec_high[0], self._sec_low[0]
```
NOTE: It is required that `Context.calc_on` function is called from `__init__` constructor method of a main or secondary
context.

If this indicator is added on a AAPL 15m chart it will draw two blue lines showing daily prices of the AAPL symbol.
There are two instrument contexts in this indicator:
* main context `Main` which is executed every time a data update on the main instrument AAPL 15m happens and
* secondary context `SecMain` which is executed every time a data update on the secondary instrument AAPL 1D happens.
Function [`Context.calc_on`](/indie/Library-reference/package-indie#func_Context_calc_on) has more parameters besides `sec_context` and `time_frame`. Here is its signature:
```txt
Context.calc_on(
sec_context: typing.Type[indie.SecContext],
exchange: indie.Optional[str] = None,
ticker: indie.Optional[str] = None,
time_frame: indie.Optional[indie.TimeFrame] = None,
lookahead: bool = False
) -> indie.SeriesF | tuple[indie.SeriesF, ...]
```
If `exchange`, `ticker` and `time_frame` are not given, then the corresponding values are taken from the current
instrument.
# null
Source: https://takeprofit.com/docs/indie/Schedules-and-Trading-Sessions
Managing trading activities in financial markets requires accounting for various time periods, such as pre-market, regular, and after-hours sessions. To efficiently manage these time periods and perform related calculations, we use the `indie.schedule.ScheduleRule`, `indie.schedule.Schedule` and `indie.TradingSession` classes.
## `ScheduleRule`
The `ScheduleRule` class defines the specific time window and list of weekdays during which it applies.
To create a `ScheduleRule` you need to specify:
* start time of the rule
* end time of the rule
* list of weekdays: we have constants `indie.schedule.WORKDAYS`, `indie.schedule.WEEKEND` and `indie.schedule.ALL_DAYS`. You can also create a custom list of weekdays as a regular list of enums, e.g. `[indie.schedule.week_day.SATURDAY, indie.schedule.week_day.SUNDAY]` (which is exactly the same as `indie.schedule.WEEKEND` by the way).
### Types of `ScheduleRule`
Depending on the start and end time values, there are three types of `ScheduleRules`.
#### Simple basic rule
Simple basic rule is a `ScheduleRule` object with `start < end`. If `end` is a midnight, then `end = time(0, 0, 0, 0)` This type of rule applies from start time to end time on specified weekdays.
Example:
```py
rule1 = ScheduleRule(start=time(hour=0), end=time(hour=5), days=ALL_DAYS) # from 00:00 am to 5:00 am everyday
rule2 = ScheduleRule(start=time(hour=9), end=time(hour=18, minute=30), days=WORKDAYS) # from 9:00 am to 6:30 pm Monday through Friday
rule3 = ScheduleRule(start=time(hour=20), end=time(hour=0), days=[week_day.WEDNESDAY]) # from 8:00 pm to 12:00 am on Wednesdays
```
#### Simple 24h rule
Simple 24-hours rule is a `ScheduleRule` object with `start == end == time(hour=0, minute=0, second=0, microsecond=0)`. This type of rule applies 24 hours on specified weekdays.
Example:
```py
rule24 = ScheduleRule(start=time(hour=0), end=time(hour=0), days=ALL_DAYS) # from 12:00 am to 12:00 am every day (24/7)
```
#### Overnight rule
Overnight rule is a `ScheduleRule` object with `start > end` or `start == end != time(hour=0, minute=0, second=0, microsecond=0)`. This type of rule applies from start time of the day before specified to end time of specified day.
Example:
```py
overnight_rule1 = ScheduleRule(start=time(hour=19), end=time(hour=7), days=[week_day.MONDAY]) # from 7:00 pm on Sunday to 7:00 am on Mondays
overnight_rule2 = ScheduleRule(start=time(hour=21), end=time(hour=3), days=WORKDAYS) # for the whole week: from 9:00 pm on Sunday to 3:00 am on Friday
overnight_rule3 = ScheduleRule(start=time(hour=15), end=time(hour=15), days=WORKDAYS) # from 3:00 pm on Sunday to 3:00 pm on Friday
```
Another way to represent an overnight rule is to use a combination of two different non-overnight rules. The first rule will have the same start time, the end time will be `time(0, 0, 0, 0)`, the second rule will have the start time equal to `time(0, 0, 0, 0)` and the end time will be the same as the original rule.
```py
overnight_rule = ScheduleRule(start=time(hour=19), end=time(hour=7), days=[week_day.MONDAY]) # from 7:00 pm on Sunday to 7:00 am on Mondays
# it is equivalent to
simple_rule1 = ScheduleRule(start=time(hour=19), end=time(hour=0), days=[week_day.SUNDAY])
simple_rule2 = ScheduleRule(start=time(hour=0), end=time(hour=7), days=[week_day.MONDAY])
```
## `Schedule`
Each `Schedule` instance defines specific time windows and exceptions to a regular schedule. To create your own schedule, you need to define:
* `rules` - a list of ScheduleRules
* `except_once` - a list of specific dates for one-time exceptions (e.g., special events or emergencies) that deviate from the usual schedule
* `except_yearly` - a list of dates representing annual exceptions (e.g., holidays)
* `timezone` - the time zone in which the schedule is defined. The time zone should be indicated according to the [IANA library standards](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (e.g., "America/New\_York" or "Europe/London").
It is quite resource-inefficient to create `Schedule` objects within the `Context.calc` method, as this would instantiate a new object on each bar, resulting in a high number of short-lived objects. Therefore, it is recommended to declare them in the `__init__` function in the class definition, which will create them once during the indicator's initialization.
Example:
```py
# indie:lang_version = 5
from indie import indicator, MainContext
from indie.schedule import ScheduleRule, Schedule, WORKDAYS, WEEKEND
from datetime import time, datetime
@indicator('Example')
class Main(MainContext):
def __init__(self):
rule1 = ScheduleRule(start=time(hour=9), end=time(hour=18), days=WORKDAYS)
rule2 = ScheduleRule(start=time(hour=12), end=time(hour=15), days=WEEKEND)
self.schedule = Schedule(rules=[rule1, rule2], except_once=[datetime(year=2025, month=4, day=5)], timezone="America/New_York")
def calc(self):
# using self.schedule, e.g.
return 1 if self.time[0] in self.schedule else 0
```
If you want to use `self.info.timezone` as the timezone in a `Schedule()`, you need to define a `pre_calc` function in your class and initialize the field inside this function. This is necessary because in the `__init__` method, `self.info` and `self.trading_session` data are not yet available.
Example:
```py
# indie:lang_version = 5
from indie import indicator, MainContext, Optional
from indie.schedule import ScheduleRule, Schedule, WORKDAYS, WEEKEND
from datetime import time, datetime
@indicator('Example')
class Main(MainContext):
def __init__(self):
self.schedule: Optional[Schedule] = None
def pre_calc(self):
rule1 = ScheduleRule(start=time(hour=9), end=time(hour=18), days=WORKDAYS)
rule2 = ScheduleRule(start=time(hour=12), end=time(hour=15), days=WEEKEND)
self.schedule = Schedule(rules=[rule1, rule2], except_once=[datetime(year=2025, month=4, day=5)], timezone=self.info.timezone)
def calc(self):
# using self.schedule, e.g.
return 1 if self.time[0] in self.schedule.value() else 0
```
`Schedule` class provides several key functionalities for working with schedules. One of the primary actions is checking whether the schedule is empty using the [`is_empty`](/indie/Library-reference/package-indie-schedule#func_Schedule_is_empty) method. Additionally, the [`in`](/indie/Library-reference/package-indie-schedule#func_Schedule_contains) operator allows you to verify if a given timestamp falls within the time periods defined by the schedule. Another useful method is [`is_same_period`](/indie/Library-reference/package-indie-schedule#func_Schedule_is_same_period), which checks whether two timestamps belong to the same schedule period or fall on different days.
## `TradingSession`
The `TradingSession` class represents the different phases of market trading. These phases correspond to specific trading windows with unique rules that vary depending on the market. It is not allowed to create objects of the `TradingSession` class in Indie code; an already created instance of the class is available in `self.trading_session`.
There are three fields in `TradingSession` class:
* `pre_market`
* `regular`
* `after_hours`
Each of these fields is an instance of the `Schedule` class. The `pre_market` and `after_hours` schedules can be empty, which can be verified using the `is_empty` method.
The main operations with `TradingSession` objects include using the [`in`](/indie/Library-reference/package-indie-schedule#func_TradingSession_contains) operator to check if a specific timestamp falls within any of the trading session periods, and the [`is_same_period`](/indie/Library-reference/package-indie-schedule#func_TradingSession_is_same_period) method to determine whether two timestamps belong to the same trading period.
The `Context` class provides four methods to determine whether the current bar is the first or last bar of a trading session:
* `is_first_in_session()`
* `is_first_in_regular_session()`
* `is_last_in_session()`
* `is_last_in_regular_session()`
If `pre_market` is empty, the `is_first_in_session` and `is_first_in_regular_session` methods will return the same value. Similarly, if `after_hours` is empty, `is_last_in_session` and `is_last_in_regular_session` will return the same value. If the first or last bar of the session does not exist or is unavailable, these methods will not return `True`.
# What is Indie?
Source: https://takeprofit.com/docs/indie/What-is-Indie
**Indie** is a *technical analysis-oriented* programming language and runtime for developing indicators for the
TakeProfit platform. All built-in indicators on the platform are implemented in Indie, and TakeProfit has integrated IDE
tools that allow users to create their own indicators.
Indie is a dialect of Python and is essentially a subset of Python language constructs, with added [syntactic
sugar](/indie/How-Indies-syntactic-sugar-works) in the form of decorators (such as `@indicator` or `@algorithm`) and a few
differences in semantics. You can learn more about these differences in [this
section](/indie/Language-differences-with-Python).
For a quick understanding of the Indie code, it is recommended to go directly to the [Quick start](/indie/Quick-start) chapter.
As a product of TakeProfit, Indie is under ongoing development and many new features and capabilities are expected to be
added in the future.
To get you started quickly, let’s write some indicators, starting with
simple examples and gradually moving on to more complex ones.
The main differences between the Python language and Indie.
An overview of the Indie library and its functions.
All changes and updates to the Indie language.