如何使用本地存储
在本文及其对应的视频中,我们将解释什么是本地存储以及如何在您的 cTrader 算法中使用它。 我们还将提供有用的示例并解释本地存储范围的工作原理。
为什么使用本地存储
在许多情况下,您希望您的算法将某些内容保存到本地文件系统或从中访问某些内容。 例如,您可能希望保存所有 cBot 操作的日志。 然而,这通常需要算法具有提升的访问权限(AccessRights.FullAccess),这对用户来说并不理想。 如果算法请求用户提供提升的权限,用户不太可能信任该算法,特别是如果它在没有源代码的情况下分发。 本地存储是一种在不引入任何安全问题的情况下安全访问本地文件系统的便捷方式。 使用本地存储允许开发人员将其算法的访问权限设置为 AccessRights.None。
在本地存储中保存字符串
每种类型的 cTrader 算法都有一个 LocalStorage 属性,允许执行读写操作。 为了演示本地存储的工作原理,我们将创建一个新的 cBot。 在其 OnStart 处理程序中,我们将使用 LocalStorage.SetString(string key, string value) 方法。 如您所见,它接受两个参数,即保存信息的键和要保存的值。
| LocalStorage.SetString("Message", Message);
|
为了检索值,我们将在 cBot 的 OnTick 处理程序中使用 GetString(string key) 方法。
| Print(LocalStorage.GetString("Message"));
|
只要 Message 不为空,我们就可以构建 cBot 并看到检索到的值正确打印在日志中。
在本地存储中保存对象
除了字符串之外,您还可以使用本地存储保存任何类型的对象。 在幕后,cTrader 在本地存储中序列化和反序列化对象,从而允许共享任何类型的数据。 为了演示这一点,我们可以创建一个新类来存储信息,保存它并在以后检索它。 我们将此类命名为 Signal。
| class Signal
{
public TradeType TradeType { get; set; }
public double SL { get; set; }
public double TP { get; set; }
}
|
在 OnStart() 方法中,我们将创建此类的新实例并初始化其属性。
| var signal = new Signal{
TradeType = TradeType.Sell,
SL = 50,
TP = 50,
};
|
我们将使用 SetObject(string key, Object object) 方法来保存和检索账户余额。
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);
}
|
如果我们构建 cBot 并启动它,我们应该看到正确的值打印在日志中。
本地存储的范围
在使用本地存储时,您还可以定义保存的值在哪个范围内暴露以供将来检索。 有三种不同的范围可供选择:
- 实例范围 - 保存的值仅对特定实例可用。
- 类型范围 - 保存的值对特定算法的所有实例可用。
- 设备范围 - 保存的值对所有算法可用,无论其类型如何。
以下是使用实例范围的示例。
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"));
}
}
|
请注意,我们已在 SetString() 方法中明确指定了范围。
我们可以添加此 cBot 的多个实例,并配置它们,以便一个实例写入本地存储,而另一个实例检索信息。 在这种情况下,读取信息应该是不可能的。 但是,如果只有一个实例被设置为执行写入和读取操作,cBot 应该按预期工作。
以下是使用类型范围的示例。
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"));
}
}
|
如果我们创建此 bot 的两个实例,并设置它们,以便一个实例写入本地存储,另一个实例读取保存的值,一切都应该正常工作,不会引发任何错误。
最后但同样重要的是,设备范围允许在不同算法之间交换信息。 以下是使用此范围类型的示例。
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"));
}
}
|
我们可以构建多个使用相同代码的 cBot。 如果我们正确设置它们,一个 cBot 可以将信息保存到本地存储,而另一个 cBot 可以检索它。 只要范围等于 LocalStorageScope.Device,我们的系统就应该按预期工作。
使用 Flush() 和 Reload() 方法
如果您想在 cTrader 的多个实例之间共享信息,请调用 Flush() 和 Reload() 方法。
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"));
}
}
|
如果我们使用此代码构建多个 cBot,并进行实验以在 cTrader 的不同实例之间共享信息,我们将看到保存的值按预期持久化。