Skip to content

How to Work With Local Storage

In this video and its corresponding article, we will talk about local storage. We will explain what local storage is and how it can be used in your cTrader algos. We will also provide useful examples and explain how local storage scope works.

Why Use Local Storage

There are many cases when you want your algo to save something to or access something from the local file system. For example, you may want to save a log of all cBot operations. However, this usually requires the algo to have elevated access rights (AccessRights.FullAccess), which is less than ideal for users. If an algo requests a user to provide elevated permissions, the user is much less likely to trust the algo, especially if it is distributed without its source code. Local storage is a convenient way to safely access the local file system without introducing any security concerns. Using local storage allows developers to keep the access rights of their algos set to AccessRights.None.

How to Save Strings in Local Storage

Every type of cTrader algo has a LocalStorage property that allows for executing read and write operations. To demonstrate how local storage works, we will create a new cBot. In its OnStart handler, we will use the LocalStorage.SetString(string key, string value) method. As you can see, it takes two arguments, namely a key under which information should be saved and the value to be saved.

1
LocalStorage.SetString("Message", Message);

To retrive the value, we will use the GetString(string key) method in the OnTick handler of the cBot.

1
Print(LocalStorage.GetString("Message"));

As long as Message is not null, we can build the cBot and see the retrieved value being correctly printed in the log.

How to Save Objects in Local Storage

Beyond string, you can use local storage to save any kind of object. Behind the scenes, cTrader serialises and deserialises objects in local storage which allows for sharing any kind of data. To demonstrate this, we can create a new class to store information, save it, and later retreived. We will name this class Signal.

1
2
3
4
5
6
class Signal
{
    public TradeType TradeType { get; set; }
    public double SL { get; set; }
    public double TP { get; set; }
}

In the OnStart() method, we will create a new instance of this class and initialise its properties.

1
2
3
4
5
var signal = new Signal{
    TradeType = TradeType.Sell,
    SL = 50,
    TP = 50,
};

We will use the SetObject(string key, Object object) method to save and retrive the account balance.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
protected override void OnStart()
{
    var signal = new Signal{
    TradeType = TradeType.Sell,
    SL = 50,
    TP = 50,
    };        

    LocalStorage.SetString("Message",Message);
    LocalStorage.SetObject("Signal 1", signal);
}

protected override void OnTick()
{
Print(LocalStorage.GetString("Message")); 

var signal = LocalStorage.GetObject<Signal>("Signal 1"); 
Print(signal.TradeType);
Print(signal.SL);
Print(signal.TP);
}

If we build our cBot and launch it, we shold see the correct values being printed in the log.

Scopes of Local Storage

When using local storage you can also define the scope in which the saved values are exposed for future retrieval. There are three different scopes available.

  • Instance scope. Saved values are only available to a specific instance.
  • Type scope. Ssaved values are available to all instances of a specific algorithm.
  • Device scope. Saved values are available to all algorithms regardless of their types.

Here is how using instance scope could look like.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[Parameter()]
public bool IsWriter { get; set; }


protected override void OnStart()
{   
    if(IsWriter)
    { 
        LocalStorage.SetString("Message",Message, LocalStorageScope.Instance);
    }
}

protected override void OnTick()
{        
    if(!IsWriter)
    {
        if(LocalStorage.GetString("Message") != string.Empty)
            Print(LocalStorage.GetString("Message"));
    }
}

Note that we have explicitly specified the scope in the SetString() method.

We can add several instances of this cBot and configure them so that one writes to local storage while another one retrieves information. In thus case, reading information should be impossible. However, if just one instance is set up to execute both write and read operationsm, the cBot should work as intended.

Here is an example of using type scope.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
protected override void OnStart()
{   
    if(IsWriter)
    {             
        LocalStorage.SetString("Message",Message, LocalStorageScope.Type);
    }
}

protected override void OnTick()
{        
    if(!IsWriter)
    {
        if(LocalStorage.GetString("Message", LocalStorageScope.Type) != string.Empty)
            Print(LocalStorage.GetString("Message"));
    }
}

If we create two instances of this bot and set them up so that one instance writes to local storage and another reads the saved value, everything should work without raising any errors.

Last but not least, device scope allows for exchanging information between different algos. Here is an example of using this scope type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
protected override void OnStart()
{   
    if(IsWriter)
    {             
        LocalStorage.SetString("Message",Message, LocalStorageScope.Device);
    }
}

protected override void OnTick()
{        
    if(!IsWriter)
    {
        if(LocalStorage.GetString("Message", LocalStorageScope.Device) != string.Empty)
            Print(LocalStorage.GetString("Message"));
    }
}

We can build several cBots that all use the same code. If we set them up correctly, one cBot can save information to local storage while another one retrieves it. As long as the scope is equal to LocalStorageScope.Device, our system should work as intended.

Using Flush() and Reload() Methods

If you want to share information between several instances of cTrader, call the Flush() and Reload() methods.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
protected override void OnStart()
{   
    if(IsWriter)
    {             
        LocalStorage.SetString("Message",Message, LocalStorageScope.Device);
        LocalStorage.Flush(LocalStorageScope.Device);
    }
}

protected override void OnTick()
{        
    if(!IsWriter)
    {
        LocalStorage.Reload(LocalStorageScope.Device);
        if(LocalStorage.GetString("Message", LocalStorageScope.Device) != string.Empty)
            Print(LocalStorage.GetString("Message"));
    }
}

If we build several cBots with this code and conduct an experiment to share information between different instances of cTrader, we will see that our saved values are persisted as intended.

As usual, we hope that you have found this article and video helpful. Subscribe to our YouTube channel to learn more about algo trading in cTrader.

Subscribe to our YouTube channel