VonmoTrade实验。 第四部分:交易图表


在过去的文章中,我们了解了如何创建和处理贸易订单。 本文的主题将是处理和存储市场分析的图形工具(股票图表)所需的信息。


在开始之前,我想做个题外话。 对于内部Vonmo项目,使用通常的V +单词命名方案,该方案最简洁地描述了项目的功能。 今天,我发现VTrade是一家现有公司。 为了避免混淆,我将实验重命名为VonmoTrade。


要评估市场状况,仅凭一本订单和交易历史记录是不够的。 我们需要一种工具,使我们能够清晰,快速地确定市场价格趋势。 交易图表可分为两种类型:


  1. 线性
  2. 间隔时间

折线图


最简单,最容易理解的时间表,无需准备。 显示金融工具价格对时间的依赖性。



这种图形的主要优点是简单。 其主要缺点是信息量低。


如果图表基于原始数据,则采用最近收盘价。 但是通常,图是基于汇总数据构建的。 在这种情况下,将采用每个间隔的收盘价。 由于我们丢弃间隔中发生的所有内容并仅采用间隔的收盘价,因此,信息内容会丢失。


图形分辨率


如果我们开始根据所有价格变化来构建图表,也就是说,每笔已完成的交易都将落在图表上,那么一个人将很难察觉到它。 并且,在处理和交付此类计划上花费的精力将被低效地利用。


因此,通过将时间轴划分为间隔并在这些间隔中汇总价格,可以精简数据。
分辨率-划分时间轴的基本间隔的大小:秒,分钟,小时,天等。


吧台


有关间隔图。 为了增加信息内容,每个时间间隔都必须在间隔的开始和结束时显示价格信息,以及最大和最小价格。 该组的图形显示称为条形图。 考虑一个酒吧的方案:



条形图形成一个图表:



日本蜡烛


像条形一样,请参阅间隔图。 它们是技术分析中最流行的图表类型。 蜡烛由黑色或白色的身体和阴影组成:上部和下部。 有时阴影称为灯芯。 阴影的上下边界显示相应时期的最高和最低价格。 主体的边界显示开盘价和收盘价。 让我们画一支蜡烛:



蜡烛的顺序形成一个图形:



OHLCV表示法


在上一篇文章中,我们找出了postgresql中该图的数据存储方案,并为将存储聚合数据的数据源创建了一个表:


CREATE TABLE df ( t timestamp without time zone NOT NULL, r df_resolution NOT NULL DEFAULT '1m'::df_resolution, o numeric(64,32), h numeric(64,32), l numeric(64,32), c numeric(64,32), v numeric(64,32), CONSTRAINT df_pk PRIMARY KEY (t, r) ) 

字段不需要解释,除了字段r是系列的分辨率。 postgresql中有枚举,当预先知道字段的一组值时,使用它们很方便。 通过枚举,我们为允许的图形分辨率定义了一种新类型。 让它成为从一分钟到一个月的系列:


 CREATE TYPE df_resolution AS ENUM ('1m', '3m', '5m', '15m', '30m', '45m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w', '1M'); 

在磁盘系统,处理器的性能和总拥有成本之间取得平衡非常重要。 系统当前定义了16种分辨率。 有两个解决方案是显而易见的:


  • 我们可以计算所有分辨率并将其存储在数据库中。 该选项很方便,因为在采样时我们不花时间在间隔的汇总上,所有数据立即准备输出。 在一个月内,将为一台仪器创建将近7.2万条记录。 看起来简单又方便,但是,这样的表会经常更改,因为每次更新价格时,都必须在表中创建或更新16个条目并重建索引。 在postgresql中,垃圾回收可能还会有问题。
  • 另一种选择是存储单个基本分辨率。 从基本分辨率中选择时,必须构建所需的分辨率。 例如,当将分钟分辨率存储为每月的基础时,将为每台仪器创建43000条记录。 因此,与以前的版本相比,记录量和开销减少了40%。 但是,处理器负载正在增加。

如上所述,找到平衡很重要。 因此,折衷方案不是存储一个基本分辨率,而是存储几个基本分辨率:1分钟,1小时,1天。 通过该方案,每个仪器每月将创建44.6万条记录。 记录音量的优化为36%,但是处理器的负载是可以接受的。 例如,要建立每周间隔而不是在一分钟基本分辨率的情况下读取和汇总10,080条记录,我们需要从磁盘读取并汇总仅7天分辨率的数据。


OHLCV储存


本质上,OHLCV是一个时间序列。 如您所知,关系数据库不太适合存储和处理此类数据。 为了解决这些问题,该项目使用Timescale扩展。


时标可以提高插入和更新操作的性能,允许您配置分区,并提供专门针对时间序列而优化的分析功能。


要创建和更新栏,我们仅需要标准功能:


  • date_trunc('minute' | 'hour' | 'day', transaction_ts) -分别找到分钟,小时和天分辨率的间隔的开始。
  • greatestleast确定最高和最低价格。

感谢upsert api,每个事务仅执行一个更新请求。
我得到了用于在基本分辨率中解决市场变化的这种SQL:


 FOR i IN 1 .. array_upper(storage_resolutions, 1) LOOP resolution = storage_resolutions[i]; IF resolution = '1m' THEN SELECT DATE_TRUNC('minute', ts) INTO bar_start; ELSIF resolution = '1h' THEN SELECT DATE_TRUNC('hour', ts) INTO bar_start; ELSIF resolution = '1d' THEN SELECT DATE_TRUNC('day', ts) INTO bar_start; END IF; EXECUTE format( 'INSERT INTO %I (t,r,o,h,l,c,v) VALUES (%L,%L,%L::numeric,%L::numeric,%L::numeric,%L::numeric,%L::numeric) ON CONFLICT (t,r) DO UPDATE SET h = GREATEST(%Ih, %L::numeric), l = LEAST(%Il, %L::numeric), c = %L::numeric, v = %Iv + %L::numeric;', df_table, bar_start, resolution, price, price, price, price, volume, df_table, price, df_table, price, price, df_table, volume ); END LOOP; 

采样时,为了汇总间隔,我们需要以下功能:


  • time_bucket分成间隔
  • first -找到开盘价O
  • max区间的最高价格H
  • min每个间隔的最低价格L
  • last -查找收盘价C
  • sum -查找交易量V

使用time_bucket时发现的唯一问题是time_bucket函数的局限性。 它仅允许您间隔不到一个月的时间进行操作。 要建立每月分辨率,必须使用标准的date_trunc函数。


API


为了在客户上显示图表,我们将使用Tradingview的轻量级图表 。 该库使您可以完全自定义图形的外观,并且使用方便。 我得到以下图表:



由于浏览器和平台之间交互的主要部分是通过websocket,因此交互性没有问题。


资料来源


图表的数据源(数据馈送)应以所需的分辨率返回时间序列的必要部分。 同时,为了节省流量并减少客户端上的处理时间,服务器必须打包点。


最初需要设计数据Feed API,以便您可以在一个请求中请求多个图表并订阅其更新。 这将减少通道中的命令和响应数量。


考虑一个最近50分钟请求USDGBP的示例,其中自动订阅了图表更新:


 { "m":"market", "c":"get_chart", "v":{ "charts":[ { "ticker":"USDGBP", "resolution":"1h", "from":0, "cnt":50, "send_updates":true } ] } } 

当然,您可以请求一个日期范围(从,到),但是由于每个小节的间隔是已知的,因此指示小节的时间和数量的声明性API对我来说似乎更方便。
此请求的数据供稿将以类似的方式响应:


 { "m":"market", "c":"chart", "v":{ "bar_fields":[ "t","uts","o","h","l","c","v" ], "items":[ { "ticker":"USDGBP", "resolution":"1h", "bars":[ [ "2019-12-13 13:00:00",1576242000,"0.75236800", "0.76926400","0.75236800","0.76926400","138.10000000" ], .... ] } ] } } 

bar_fields字段包含有关元素位置的信息。 进一步的优化是将该字段放在启动时从服务器接收的客户端配置中。


因此,客户端接收历史数据的必要部分并建立图形的初始状态。 如果状态发生变化,他将收到仅影响最后一根柱的更新。


 { "m":"market", "c":"chart_tick", "v":{ "ticker":"USDGBP", "resolution":"1h", "items":{ "v":"140.600", "ut":1576242000, "t":"2019-12-13T13:00:00", "o":"0.752368", "l":"0.752368", "h":"0.770531", "c":"0.770531" } } } 

初步结果


在整个系列文章中,我们一直在分析建立交流的理论和实践。 现在是将系统组合在一起的时候了。


在下一篇文章中,我们将讨论图形用户界面的开发:用于平台管理的服务UI和用于最终用户的UI。 还将演示Vonmo Trade的演示版本。

Source: https://habr.com/ru/post/zh-CN483308/


All Articles