# Tutorial: Create indicator with Cursor IDE

### Introduction

Cursor IDE is a fork of VS Code that has powerful AI capabilities, allowing it to access your code directly and have information about your project.

Cursor can also be provided with FTO custom indicator documentation to assist in creating new indicators.

{% hint style="info" %}
Please note that Cursor is a paid IDE, but it has a free version, the free version is limited to 50 requests\
and 2000 completions total.
{% endhint %}

### Step 1: Install Cursor and set up the project

How to install Cursor and set up the project is described in [this](/fto-indicators-docs/setup-and-installation.md) guide. If you don’t yet know how to set up your environment to work with the FTO API for indicators, that is also covered in the same guide.

### Step 2: Apply Cursor Rules

The [**Rules**](https://docs.cursor.com/context/rules-for-ai) feature in Cursor IDE allows users to define custom guidelines or behaviors that the AI should follow when generating code. By setting up rules that describe how indicators work in FTO, you can effectively teach Cursor the context it needs to produce accurate and consistent indicators.

To set up global rules for Cursor, click the setting icon (Picture #1)

<figure><img src="/files/LpZvQsRwfn89wKKxelNU" alt=""><figcaption><p>Picture #1</p></figcaption></figure>

From here, click the Rules setting (Picture #2)\\

<figure><img src="/files/44uoTKOe6uilBPe0Co2p" alt=""><figcaption><p>Picture #2</p></figcaption></figure>

In the User Rules field (Picture #3), download and paste contents of the file below called Rules.txt

{% file src="/files/yu0njIINlJovwrAczL1L" %}

<figure><img src="/files/Jz9A3kFHPDvaoi3Ba0Nl" alt=""><figcaption><p>Picture #3</p></figcaption></figure>

### Step 3: Upload FTO indicator documentation to Cursor

You can upload the FTO indicator documentation to Cursor, and Cursor will be able to use it to help you create new indicators.

To upload the FTO indicator documentation to Cursor, you need to follow these steps:

1\. Click the setting icon in the top right corner of the Cursor IDE. (Picture #4)

<figure><img src="/files/6Zz25Q4G5A74sO66t66X" alt=""><figcaption><p>Picture #4</p></figcaption></figure>

2\. Select "Features" on the left sidebar (Picture #5).

<figure><img src="/files/rZ4jeRLGw7pcZxKbOl13" alt=""><figcaption><p>Picture #5</p></figcaption></figure>

3. Scroll down until you see Docs (Picture #6)

<figure><img src="/files/7s506JYBsCSycXBY4wiX" alt=""><figcaption><p>Picture #6</p></figcaption></figure>

4. Click on the "**Add new doc**" button and insert link <https://fto-2.gitbook.io/fto-indicators-docs> to the FTO indicator documentation (Picture #7).

<figure><img src="/files/yTIoNcfykk34kpJ5Uway" alt=""><figcaption><p>Picture #7</p></figcaption></figure>

After some indexing, Cursor will be able to refer to the documentation to help you create new indicators.

To become more familiar with how to use this added documentation in your requests to Cursor, go to the [Recommendations ](#recommendations)section below.

### Step 4: Getting familiar with Cursor

To open Cursors AI window, you can press `Ctrl+L` or click on the icon in the top right corner of the Cursor IDE (Picture #8)

<figure><img src="/files/K16QM2tL90LzjlgmuSoL" alt=""><figcaption><p>Picture #8</p></figcaption></figure>

This panel has a chat interface and in Cursor version 0.47.8 it has 3 modes, **Agent**, **Ask** and **Edit,**

each catering to different needs during development (Picture #9).

* **Agent Mode:** This mode allows for automated code generation and completion by interacting with the AI. It helps streamline the coding process by providing intelligent suggestions and solutions. I access your project files directly and suggests code which you can accept or reject
* **Ask Mode:** In this mode, developers can ask questions about their codebase, programming concepts, or any development-related topics. The AI will respond with helpful guidance and explanations.
* **Edit Mode:** Edit Mode assists in making modifications to the existing code. It aids in refactoring, simplifying, or improving code sections as needed.

What makes these modes powerful is the ability to add context directly from your project or documentation

For now, select the **Ask** mode

<figure><img src="/files/7Zc1aUAOvW0of1qvkdkR" alt=""><figcaption><p>Picture #9</p></figcaption></figure>

Next to the "select mode menu" there is also an option to select a model of AI that we want to use, for now we should choose **Auto-select** (Picture#10).

<figure><img src="/files/gnmtQ32XMTezuwQb1jCh" alt=""><figcaption><p>Picture #10</p></figcaption></figure>

### Step 5: Start building

Before we begin writing the indicator, it is expected that you are familiar with how to set up the environment to access the FTO Indicator API. If not, please read [this](/fto-indicators-docs/setup-and-installation.md) guide first before continuing.

For this example, we will ask Cursor to implement the On Balance Volume (OBV) indicator for us. In this guide, we will start with an empty file, but for future indicator implementations, you can use some of our indicator foundations provided in [this section](/fto-indicators-docs/download-indicator-examples.md).

In the request to create the OBV indicator for us, I included the FTO documentation for [context](#recommendations) and added the [Rules](#step-2-apply-cursor-rules) discussed earlier. In the screenshot, you can see the sections of the documentation it decided to use (Picture #11).

<figure><img src="/files/XIx9ujKwh9OH1GLZKraB" alt=""><figcaption><p>Picture #11</p></figcaption></figure>

In the result, we got code below

```typescript
import { IndicatorImplementation, TDrawStyle, TPenStyle, TOutputWindow, TIndexBuffer } from "forex-tester-custom-indicator-api";

export default class OBVIndicator extends IndicatorImplementation {
    // Declare the buffer as a class property
    public obvBuffer!: TIndexBuffer;

    Init(): void {
        this.api.RecalculateMeAlways();
        
        // Set indicator name
        this.api.IndicatorShortName("On Balance Volume (OBV)");
        
        // Configure to display in separate window since OBV is an oscillator
        this.api.SetOutputWindow(TOutputWindow.SEPARATE_WINDOW);
        
        // Register the number of buffers we'll use
        this.api.IndicatorBuffers(1);
        
        // Create and initialize the OBV buffer
        this.obvBuffer = this.api.CreateIndexBuffer();
        
        // Bind buffer to index 0
        this.api.SetIndexBuffer(0, this.obvBuffer);
        
        // Configure buffer appearance
        this.api.SetIndexStyle(0, TDrawStyle.LINE, TPenStyle.SOLID, 1, "#0000FF"); // Blue line
        this.api.SetIndexLabel(0, "OBV");
    }

    Calculate(index: number): void {
        // If this is the first bar (rightmost/newest), initialize OBV
        if (index === this.api.Bars() - 1) {
            this.obvBuffer.setValue(index, this.api.Volume(index));
            return;
        }

        // Get current and previous close prices
        const currentClose = this.api.Close(index);
        const previousClose = this.api.Close(index + 1);
        
        // Get current volume
        const volume = this.api.Volume(index);
        
        // Get previous OBV value
        const previousOBV = this.obvBuffer.getValue(index + 1);
        
        let currentOBV;
        
        // Calculate OBV based on price movement
        if (currentClose > previousClose) {
            // If price increased, add volume
            currentOBV = previousOBV + volume;
        } else if (currentClose < previousClose) {
            // If price decreased, subtract volume
            currentOBV = previousOBV - volume;
        } else {
            // If price unchanged, OBV remains the same
            currentOBV = previousOBV;
        }
        
        // Set the calculated OBV value
        this.obvBuffer.setValue(index, currentOBV);
    }
}
```

The current logic seems correct, but it's using only the Close price, and there is currently no way for the user to specify their own price type. Let's ask it to fix that (Picture #12).

<figure><img src="/files/xiFIRVhIExTC4LucAqw0" alt=""><figcaption><p>Picture #12</p></figcaption></figure>

The code that Cursor wrote in his second response is below

```typescript
import { 
    IndicatorImplementation, 
    TDrawStyle, 
    TPenStyle, 
    TOutputWindow, 
    TIndexBuffer,
    TOptionType,
    TOptValue_number
} from "forex-tester-custom-indicator-api";

export default class OBVIndicator extends IndicatorImplementation {
    // Declare the buffer as a class property
    public obvBuffer!: TIndexBuffer;
    
    // Declare price type parameter
    public priceType!: TOptValue_number;

    Init(): void {
        this.api.RecalculateMeAlways();
        
        // Set indicator name
        this.api.IndicatorShortName("On Balance Volume (OBV)");
        
        // Configure to display in separate window since OBV is an oscillator
        this.api.SetOutputWindow(TOutputWindow.SEPARATE_WINDOW);
        
        // Initialize price type parameter
        this.priceType = this.api.createTOptValue_number(0); // Default to Close price
        
        // Register price type parameter as an enum
        this.api.RegOption(
            "Price Type",
            TOptionType.ENUM_TYPE,
            this.priceType
        );
        
        // Add price type options
        this.api.AddOptionValue("Price Type", "Close");
        this.api.AddOptionValue("Price Type", "Open");
        this.api.AddOptionValue("Price Type", "High");
        this.api.AddOptionValue("Price Type", "Low");
        this.api.AddOptionValue("Price Type", "Median ((H+L)/2)");
        this.api.AddOptionValue("Price Type", "Typical ((H+L+C)/3)");
        
        // Register the number of buffers we'll use
        this.api.IndicatorBuffers(1);
        
        // Create and initialize the OBV buffer
        this.obvBuffer = this.api.CreateIndexBuffer();
        
        // Bind buffer to index 0
        this.api.SetIndexBuffer(0, this.obvBuffer);
        
        // Configure buffer appearance
        this.api.SetIndexStyle(0, TDrawStyle.LINE, TPenStyle.SOLID, 1, "#0000FF"); // Blue line
        this.api.SetIndexLabel(0, "OBV");
    }

    private getPrice(index: number): number {
        switch (this.priceType.value) {
            case 0: // Close
                return this.api.Close(index);
            case 1: // Open
                return this.api.Open(index);
            case 2: // High
                return this.api.High(index);
            case 3: // Low
                return this.api.Low(index);
            case 4: // Median
                return (this.api.High(index) + this.api.Low(index)) / 2;
            case 5: // Typical
                return (this.api.High(index) + this.api.Low(index) + this.api.Close(index)) / 3;
            default:
                return this.api.Close(index); // Fallback to Close
        }
    }

    Calculate(index: number): void {
        // If this is the first bar (rightmost/newest), initialize OBV
        if (index === this.api.Bars() - 1) {
            this.obvBuffer.setValue(index, this.api.Volume(index));
            return;
        }

        // Get current and previous prices using selected price type
        const currentPrice = this.getPrice(index);
        const previousPrice = this.getPrice(index + 1);
        
        // Get current volume
        const volume = this.api.Volume(index);
        
        // Get previous OBV value
        const previousOBV = this.obvBuffer.getValue(index + 1);
        
        let currentOBV;
        
        // Calculate OBV based on price movement
        if (currentPrice > previousPrice) {
            // If price increased, add volume
            currentOBV = previousOBV + volume;
        } else if (currentPrice < previousPrice) {
            // If price decreased, subtract volume
            currentOBV = previousOBV - volume;
        } else {
            // If price unchanged, OBV remains the same
            currentOBV = previousOBV;
        }
        
        // Set the calculated OBV value
        this.obvBuffer.setValue(index, currentOBV);
    }
}
```

And with the addition of this new parameter and internal method, we get a nice dropdown with price types (Picture #13).

<figure><img src="/files/zaFRDffYZZgwMdn8qpCr" alt=""><figcaption><p>Picture #13</p></figcaption></figure>

\
So in the end, we got a proper indicator with just two simple requests by setting up Cursor properly and providing it with [Rules](#step-2-apply-cursor-rules) and documentation for context.

### Recommendations

For Cursor to use the documentation that we provided in [Step 3](#step-3-upload-fto-indicator-documentation-to-cursor) we need to do the following:

Start by selecting the Ask mode and add context to your query by typing @ and selecting Docs from the drop-down menu (Picture #14).

<figure><img src="/files/LY30Rid4babOoIFC1Gmh" alt=""><figcaption><p>Picture #14</p></figcaption></figure>

In the drop-down menu, select FTO Indicator documentation, which we added earlier in [Step 3 ](#step-3-upload-fto-indicator-documentation-to-cursor)(Picture#15)

<figure><img src="/files/DZKYvLTtrM6jUYcJQIWx" alt=""><figcaption><p>Picture #15</p></figcaption></figure>

And provide add a file in which you want to create the indicator, you can do it by drag and dropping it from explorer window on the left onto the chat window or finding it in the @ drop-down menu under **Files & folders** (Picture #16)

<figure><img src="/files/xZvh0OxuKjOL76L2rTXt" alt=""><figcaption><p>Picture #16</p></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fto-2.gitbook.io/fto-indicators-docs/tutorial-create-indicator-with-cursor.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
