跳转至

网络访问

本指南定义了如何创建可以访问互联网的算法。 以下是这个 API 功能的一分钟总结。

一分钟了解网络访问!

  • 您的算法解决方案可以从交易新闻网站或外汇相关的网络 API 获取信息。 使用此功能确保您的 cBot、插件和指标对紧迫的现实事件和信息做出反应。
  • 通过使用 System.Text.Json 和 System.Text.Json.Serialization 命名空间中的方法,您可以快速地将对象序列化或反序列化为 JSON 文件,使 cBot 能够轻松消费端点并处理有价值的信息。
  • WebSocket 协议允许实时从服务接收数据,而不是每次都必须发出 HTTP 请求。 使用 websocket 可以顺利地将您的算法与网络资源集成。 WebSocketClient 类包含使用 websocket 连接所需的所有方法和参数。
  • 使用 websocket 时,您可以发送和接收字符串和原始字节数据。 处理不同的数据结构并将它们序列化为字节,以使用有价值的第三方服务。
  • AccessRights.None 足以满足网络功能。

HTTP

新的 Http 接口包含几个方法,实现后应该能够使 cBot 和其他类型的算法访问互联网。 举例说明如下:

  • HttpResponse Http.Get(string uri)。 对传入的字符串 uri 中指定的 URI 执行 GET 请求,并返回包含此请求结果的 HttpsResponse 对象。

HttpsRequest 类允许执行更复杂的请求,包括 POST 请求。 要执行这些请求,请将 HttpsRequest.Method 属性设置为 HttpMethod enum 的值之一,如 HttpMethod.Put 或 HttpMethod.Patch。

相应地,HttpsRequest.Uri 属性包含发送请求的 URI,而 HttpsRequest.Body 属性可用于设置请求主体。 请参见下面的示例,了解如何使用 HttpsRequest 对象。

  • HttpResponse Http.Send(HttpRequest request)。 对传入此方法的 HttpsRequest 对象的 request.Uri 属性值指定的 URI 执行请求。 之后,返回包含此请求结果的 HttpsResponse 对象。 请求类型设置为 equest.Method 属性的值。

回测和优化中的网络访问

Http 接口中的所有方法在回测和优化中都能按预期工作。 请注意,在回测或优化中访问网络资源时,将请求该资源的最新版本,而不是历史版本。

创建示例 cBots

执行 GET 请求

我们将创建一个简单的 cBot,执行以下操作:

  • 发送 GET 请求并通过 API 访问 https://forexApiExample.com/v1/exchangerate 的 JSON 文件(请注意,这个 API 完全是虚构的)。
  • 如果 GET 响应成功,cBot 将响应体反序列化为自定义 SymbolPrice 类的对象(我们创建这个类是为了演示目的)。
  • 在略高于 API 指定价格的价位为某个交易品种下达限价卖单。

请注意,这个 cBot 完全是虚构的。 虽然代码可以编译,但不会执行任何有意义的操作。

如何将字符串与 JSON 文件进行序列化或反序列化

我们的 cBot 代码包含两个重要的 using 语句,即 System.Text.Json 和 System.Text.Json.Serialization。 这些命名空间包含几个方法,可以轻松地将字符串与 JSON 文件进行序列化和反序列化,例如 JsonSerializer.Deserialize<T>()。

以下是我们示例 cBot 的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NetworkAccessTest : Robot
    {

        protected override void OnStart()
        {

            var responseToGet = Http.Get("https://forexApiExample.com/v1/exchangerate");

            if (responseToGet.IsSuccessful)
            {
                var tradedSymbol = JsonSerializer.Deserialize<SymbolPrice>(responseToGet.Body);
                var result = PlaceLimitOrder(TradeType.Sell, tradedSymbol.SymbolName, 10000, tradedSymbol.ConversionRate + 0.15);

            }
        }
    }

    public class SymbolPrice
    {
        public string SymbolName { get; set; }
        public double ConversionRate { get; set; }
    }
}

如果这个 cBot 要访问真实的 API,它会成功完成。

执行 POST 请求

我们还可以创建一个更高级的 cBot,实现以下目标:

  • 向同一个虚构的 API https://anotherForexApiExample.com/commodities/v1/getaccesstoken 发送 POST 请求。 这是为了获取该 API 的访问令牌。
  • 将响应体中的令牌存储在 token 变量中。
  • 向同一 API 执行 GET 请求,将 token 变量的值作为查询参数传递到 URI 中(https://anotherForexApiExample.com/commodities/v1/getprices)。
  • 使用 JSON 序列化(如上所述),在略低于从 API 接收到的价格处下达买入止损单。

再次注意,这个 cBot 在编译后不会执行任何有意义的操作。 它仅用于示例目的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NetworkAccessTestTwo : Robot
    {

        protected override void OnStart()
        {
            var uriForAccessToken = new Uri("https://anotherForexApiExample.com/commodities/v1/getaccesstoken");

            var postRequest = new HttpRequest(uriForAccessToken);

            postRequest.Method = HttpMethod.Post;

            var responseToPost = Http.Send(postRequest);

            var token = responseToPost.Body;

            var response = Http.Get($"https://anotherForexApiExample.com/commodities/v1/getprices?token={token}");

            if (response.IsSuccessful)
            {
                var tradedSymbol = JsonSerializer.Deserialize<SymbolPrice>(response.Body);

                var result = PlaceStopOrder(TradeType.Buy, tradedSymbol.SymbolName, 10000, tradedSymbol.ConversionRate - 0.15);

            }
        }
    }

    public class SymbolPrice
    {
        public string SymbolName { get; set; }
        public double ConversionRate { get; set; }
    }
}

WebSocket 客户端

Algo API 允许任何人使用 WebSocket 连接来使用各种 Web 服务和资源。 与在网络访问功能中使用的 HTTP 协议相比,WebSocket 协议更快,并允许实时接收数据。

使用 WebSocket 客户端

使用 WebSocket 客户端很简单:

  1. 选择一个暴露 WebSocket 连接端点的服务
  2. 初始化 WebSocketClientOptions 类的对象,并指定其参数以配置您的客户端。
  3. 初始化 WebSocketClient 类的对象,并将先前创建的选项传递给构造函数。
  4. 使用 Connect() 方法连接到您选择的资源,并通过 Send() 方法发送数据。
  5. 使用 TextReceived() 和 BinaryReceived() 事件处理程序来设置当 WebSocket 客户端接收到新数据时您的算法应该做什么。

下面,我们将创建一个简单的 cBot,通过 WebSocket 连接到一个虚构的经济新闻服务。 当发布了一条关于 cBot 当前附加的交易品种的新消息时,算法将显示一个包含新闻文本的消息框。

注意

这个 cBot 仅用于示例目的。 虽然它可以成功构建,但在附加到图表时不会执行任何操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class ExampleWebSocketBot : Robot
    {

        private static WebSocketClientOptions _webSocketClientOptions = new WebSocketClientOptions 
        {
            KeepAliveInterval = new TimeSpan(0, 1, 30),
            UseDefaultCredentials = true,
        };
        private WebSocketClient _webSocketClient = new WebSocketClient(_webSocketClientOptions);
        private readonly Uri _targetUri = new Uri("ws://amazingnews.com:8000");

        protected override void OnStart()
        {
            _webSocketClient.Connect(_targetUri);
            _webSocketClient.Send("Hello");
            _webSocketClient.TextReceived += NewsReceived;
        }

        protected override void OnStop()
        {
            _webSocketClient.Close(WebSocketClientCloseStatus.NormalClosure);
        }

        private void NewsReceived(WebSocketClientTextReceivedEventArgs args) 
        {
            if (args.Text.Contains(SymbolName)) 
            {
                MessageBox.Show(args.Text, "News!", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
            }
        }
    }
}

如您所见,我们的代码非常简洁,因为我们可以处理 WebSocketClient.TextReceived 事件来显示消息框。 请注意,我们的 cBot 不会主动从服务请求信息。 相反,它会动态地对提供给它的新信息做出反应。

警告

当您的 WebSocket 客户端因任何原因断开连接(例如服务器端错误导致超过保持活动间隔)时,您需要再次调用 WebSocketClient.Connect() 方法。 要以编程方式处理此类情况,请使用 WebSocketClient.Disconnected 事件。

WebSocket 的优势

由于 WebSocket 允许实时对来自网络的新数据做出反应,因此它非常适合与可以自主通知您的算法某些事情的第三方服务集成。 以下是您可以使用 WebSocket 客户端的一些网络资源示例。

  • 经济新闻日历。 当发布新消息时,您的算法可以显示一个包含关键信息的消息框。
  • 生成式 AI 服务。 当 AI 服务开始对提示做出响应时,您可以逐字显示结果,而不必等待完整的响应。
  • 与算法附加的交易品种相关的所有交易品种的价格流。 当价格更新时,它们会立即准确地显示给算法用户。
  • 专注于交易的社交媒体网络。 当发布关于特定交易品种的新消息时,算法可以向用户显示其内容。

总的来说,与常规 HTTPS 相比,WebSocket 连接提供以下优势:

  • WebSocket 连接更高效。 任何 HTTP 请求都必须包含额外的数据,如头部。 使用 WebSocket,您的连接只建立一次,之后就不需要发送冗余数据。
  • WebSocket 连接提供更好的并发性。 发送 HTTP 请求后,不需要暂停算法操作直到等待响应。 使用 WebSocket,您可以随时发送和接收数据,并异步处理它。

WebSocket 客户端允许所有类型的算法动态地与网络资源交互;与使用 HTTP 相比,这种交互更快、更高效。 使用 WebSocket 客户端构建强大的算法,与第三方服务集成。

网络访问和 AccessRights 属性

简而言之,AccessRights enum 定义了算法是否可以访问 cTrader 外部的数据,如本地机器的文件系统。 您可以在本教程中了解更多信息。

将 AccessRights 设置为 AccessRights.FullAccess 允许算法执行高级操作(如从 Windows 注册表获取信息)。 然而,最终用户可能会认为给予 cBots 或指标完全访问权限是有风险的,因为这可能导致数据泄露。

因此,如果您想与他人分享您的算法产品,AccessRights.None 通常是最明智的选择。 但是,即使您选择此选项,您的 cTrader 产品仍可自由访问网络。 将网络访问功能添加到 cTrader Algo API 意味着 cBots 不再需要将 AccessRights 属性设置为 AccessRights.FullAccess 就可以使用互联网资源。

这大大扩展了算法开发人员在编写打算分发给其他交易者的 cTrader 产品时的机会。

摘要

总之,网络访问是一个强大的功能,它允许大大扩展您的算法可以执行的操作数量,同时不会引入额外的风险。