# VWAP

```
//------------------------------------------------------------------------------
//
// Индикатор VWAP. Copyright (c) 2023 Tiger Trade Capital AG. All rights reserved.
//
//------------------------------------------------------------------------------
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows.Media;
using TigerTrade.Chart.Base;
using TigerTrade.Chart.Base.Enums;
using TigerTrade.Chart.Indicators.Common;
using TigerTrade.Chart.Indicators.Drawings;
using TigerTrade.Chart.Indicators.Drawings.Enums;
using TigerTrade.Chart.Indicators.Enums;
using TigerTrade.Core.Utils.Time;
 
namespace TigerTrade.Chart.Indicators.Custom
{
    [DataContract(Name = "VWAPIndicator", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    [Indicator("X_VWAP", "*VWAP", true, Type = typeof(VWAPIndicator))]
    internal sealed class VWAPIndicator : IndicatorBase
    {
        private IndicatorPeriodType _period;
 
        [DataMember(Name = "Period")]
        [Category("Параметры"), DisplayName("Период")]
        public IndicatorPeriodType Period
        {
            get => _period;
            set
            {
                if (value == _period)
                {
                    return;
                }
 
                _period = value;
 
                StdDevCache.Clear();
 
                OnPropertyChanged();
            }
        }
 
        private TimeSpan? _startTime;
 
        [DataMember(Name = "StartTime")]
        [Category("Параметры"), DisplayName("Время")]
        public TimeSpan? StartTime
        {
            get => _startTime;
            set
            {
                if (value.Equals(_startTime))
                {
                    return;
                }
 
                _startTime = value;
 
                StdDevCache.Clear();
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorPriceType _priceType;
 
        [DataMember(Name = "PriceType")]
        [Category("Параметры"), DisplayName("Цена")]
        public IndicatorPriceType PriceType
        {
            get => _priceType;
            set
            {
                if (value == _priceType)
                {
                    return;
                }
 
                _priceType = value;
 
                StdDevCache.Clear();
 
                OnPropertyChanged();
            }
        }
 
        private List<decimal> _stdDevs;
 
        [DataMember(Name = "StdDevs")]
        [Category("Параметры"), DisplayName("StdDevs")]
        public List<decimal> StdDevs
        {
            get => _stdDevs ?? (StdDevs = new List<decimal>());
            set
            {
                if (Equals(value, _stdDevs))
                {
                    return;
                }
 
                _stdDevs = value;
             
                OnPropertyChanged();
            }
        }
 
        private ChartSeries _vwapSeries;
 
        [DataMember(Name = "VWAP")]
        [Category("ChartIndicatorsCharts"), DisplayName("VWAP")]
        public ChartSeries VWAPSeries
        {
            get => _vwapSeries ?? (_vwapSeries = new ChartSeries(ChartSeriesType.Line, Colors.Blue));
            private set
            {
                if (Equals(value, _vwapSeries))
                {
                    return;
                }
 
                _vwapSeries = value;
 
                OnPropertyChanged();
            }
        }
 
        private ChartSeries _stdDevSeries;
     
        [DataMember(Name = "StdDev")]
        [Category("ChartIndicatorsCharts"), DisplayName("StdDev")]
        public ChartSeries StdDevSeries
        {
            get => _stdDevSeries ?? (_stdDevSeries = new ChartSeries(ChartSeriesType.Line, Colors.Red));
            private set
            {
                if (Equals(value, _stdDevSeries))
                {
                    return;
                }
 
                _stdDevSeries = value;
 
                OnPropertyChanged();
            }
        }
 
        public VWAPIndicator()
        {
            Period = IndicatorPeriodType.Day;
 
            StartTime = null;
 
            PriceType = IndicatorPriceType.Median;
 
            StdDevs.Add(1);
            StdDevs.Add(2);
        }
 
        private List<double> _stdDevCache;
     
        private List<double> StdDevCache => _stdDevCache ?? (_stdDevCache = new List<double>(1000));
 
        protected override void Execute()
        {
            var date = Helper.Date;
            var price = Helper.Price(_priceType);
            var vol = Helper.Volume;
 
            var vwap = new double[date.Length];
            var stdDev = new double[date.Length];
            var splits = new bool[date.Length];
 
            var calcStdDevs = StdDevs.Count > 0;
 
            if (date.Length < StdDevCache.Count)
            {
                StdDevCache.Clear();
            }
 
            var lastSequence = -1;
 
            var cumVolumePrice = 0.0;
            var cumVolume = 0.0;
 
            var newDayIndex = 0;
 
            double timeOffset;
 
            if (StartTime.HasValue)
            {
                var oaBaseDate = DateTime.FromOADate(0);
 
                timeOffset = -oaBaseDate.Add(StartTime.Value).ToOADate();
            }
            else
            {
                timeOffset = TimeHelper.GetSessionOffset(DataProvider.Symbol.Exchange);
            }
 
            for (var i = 0; i < date.Length; i++)
            {
                var sequence = -1;
 
                switch (Period)
                {
                    case IndicatorPeriodType.Day:
 
                        sequence = DataProvider.Period.GetSequence(ChartPeriodType.Day, 1, date[i], timeOffset);
 
                        break;
 
                    case IndicatorPeriodType.Week:
 
                        sequence = DataProvider.Period.GetSequence(ChartPeriodType.Week, 1, date[i], timeOffset);
 
                        break;
 
                    case IndicatorPeriodType.Month:
 
                        sequence = DataProvider.Period.GetSequence(ChartPeriodType.Month, 1, date[i], timeOffset);
 
                        break;
                }
 
                if (sequence != lastSequence)
                {
                    lastSequence = sequence;
 
                    newDayIndex = i;
 
                    cumVolumePrice = 0.0;
                    cumVolume = 0.0;
 
                    splits[i] = true;
                }
 
                cumVolumePrice += price[i] * vol[i];
                cumVolume += vol[i];
 
                if (cumVolume == 0)
                {
                    continue;
                }
 
                vwap[i] = cumVolumePrice / cumVolume;
 
                if (calcStdDevs)
                {
                    if (i < StdDevCache.Count)
                    {
                        stdDev[i] = StdDevCache[i];
                    }
                    else
                    {
                        var variance = 0.0;
 
                        for (var j = newDayIndex; j < i; j++)
                        {
                            variance += (vol[j]/cumVolume)*(price[j] - vwap[i])*(price[j] - vwap[i]);
                        }
 
                        stdDev[i] = Math.Sqrt(variance);
 
                        StdDevCache.Add(stdDev[i]);
                    }
                }
            }
 
            var vwapSeries = new IndicatorSeriesData(vwap, VWAPSeries)
            {
                Style =
                {
                    DisableMinMax = true
                }
            };
 
            Series.Add(vwapSeries);
 
            if (calcStdDevs)
            {
                foreach (var dev in StdDevs)
                {
                    if (dev <= 0)
                    {
                        continue;
                    }
 
                    var stdDevPos = new double[date.Length];
                    var stdDevNeg = new double[date.Length];
 
                    var d = (double) dev;
 
                    for (var i = 0; i < date.Length; i++)
                    {
                        stdDevPos[i] = vwap[i] + stdDev[i] * d;
                        stdDevNeg[i] = vwap[i] - stdDev[i] * d;
                    }
 
                    var stdDevPosSeries = new IndicatorSeriesData(stdDevPos, StdDevSeries)
                    {
                        Style = {DisableMinMax = true}
                    };
 
                    var stdDevNegSeries = new IndicatorSeriesData(stdDevNeg, StdDevSeries)
                    {
                        Style = {DisableMinMax = true}
                    };
 
                    Series.Add(stdDevPosSeries, stdDevNegSeries);
                }
            }
 
            foreach (var series in Series)
            {
                series.UserData["S"] = splits;
                series.UserData["SE"] = false;
            }
        }
 
        public override void ApplyColors(IChartTheme theme)
        {
            VWAPSeries.AllColors = theme.GetNextColor();
            StdDevSeries.AllColors = theme.GetNextColor();
 
            base.ApplyColors(theme);
        }
 
        public override void CopyTemplate(IndicatorBase indicator, bool style)
        {
            var i = (VWAPIndicator)indicator;
 
                       Period = i.Period;
            PriceType = i.PriceType;
 
            StdDevs = i.StdDevs.ToList();
 
            VWAPSeries.CopyTheme(i.VWAPSeries);
            StdDevSeries.CopyTheme(i.StdDevSeries);
 
            base.CopyTemplate(indicator, style);
        }
    }
}
```


---

# 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://support.tiger.com/razrabotka-dlya-tiger.trade-windows/primery-indikatorov/vwap.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.
