namespace ATAS.Indicators.Technical
{
using ATAS.Indicators.Drawing;
using OFT.Attributes;
using OFT.Localization;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using CrossColor = System.Windows.Media.Color;
public enum Side
{
Buy,
Sell
}
[DisplayName(“COT High/LowAtas”)]
[Display(ResourceType = typeof(Strings), Description = nameof(Strings.RatioDescription))]
[HelpLink(“https://help.atas.net/en/support/solutions/articles/72000602282”)]
public class CotHighAtas : Indicator
{
#region Nested types
private class RatioSign
{
public readonly int Bar;
public readonly int Direction;
public readonly double Price;
public readonly double Ratio;
public RatioSign(int bar, int direction, double ratio, double price)
{
Bar = bar;
Direction = direction;
Ratio = ratio;
Price = price;
}
}
#endregion
#region Static and constants
public const int Call = 1;
public const int Put = -1;
public const int Wait = 0;
#endregion
#region Fields
private CrossColor _bgColor = DefaultColors.Yellow.Convert();
private int _days = 20;
private int _fontSize = 10;
private CrossColor _highColor = DefaultColors.Blue.Convert();
private CrossColor _lowColor = DefaultColors.Green.Convert();
private decimal _lowRatio = 0.71m;
private CrossColor _neutralColor = DefaultColors.Gray.Convert();
private decimal _neutralRatio = 29m;
private int _targetBar;
public int CallPutCount;
#endregion
#region Properties
[Display(ResourceType = typeof(Strings), GroupName = nameof(Strings.Settings), Name = nameof(Strings.LowRatio), Description = nameof(Strings.LowRatioDescription), Order = 20)]
public decimal LowRatio
{
get => _lowRatio;
set
{
_lowRatio = value;
ReDraw();
}
}
[Display(ResourceType = typeof(Strings), GroupName = nameof(Strings.Settings), Name = nameof(Strings.NeutralRatio), Description = nameof(Strings.HighRatioDescription), Order = 21)]
public decimal NeutralRatio
{
get => _neutralRatio;
set
{
_neutralRatio = value;
ReDraw();
}
}
[Display(ResourceType = typeof(Strings), GroupName = nameof(Strings.Calculation), Name = nameof(Strings.DaysLookBack), Order = int.MaxValue, Description = nameof(Strings.DaysLookBackDescription))]
[Range(0, 1000)]
public int Days
{
get => _days;
set
{
if (value < 0)
return;
_days = value;
RecalculateValues();
}
}
[Display(ResourceType = typeof(Strings), GroupName = nameof(Strings.Colors), Name = nameof(Strings.LowColor), Description = nameof(Strings.LowRatioColorDescription), Order = 10)]
public CrossColor LowColor
{
get => _lowColor;
set
{
_lowColor = value;
ReDraw();
}
}
[Display(ResourceType = typeof(Strings), GroupName = nameof(Strings.Colors), Name = nameof(Strings.NeutralColor), Description = nameof(Strings.NeutralRatioColorDescription), Order = 11)]
public CrossColor NeutralColor
{
get => _neutralColor;
set
{
_neutralColor = value;
ReDraw();
}
}
[Display(ResourceType = typeof(Strings), GroupName = nameof(Strings.Colors), Name = nameof(Strings.HighColor), Description = nameof(Strings.HighRatioColorDescription), Order = 12)]
public CrossColor HighColor
{
get => _highColor;
set
{
_highColor = value;
ReDraw();
}
}
[Display(ResourceType = typeof(Strings), GroupName = nameof(Strings.Colors), Name = nameof(Strings.BackGround), Description = nameof(Strings.FillColorDescription), Order = 13)]
public CrossColor BackgroundColor
{
get => _bgColor;
set
{
_bgColor = value;
ReDraw();
}
}
[Display(ResourceType = typeof(Strings), GroupName = nameof(Strings.Colors), Name = nameof(Strings.FontSize), Description = nameof(Strings.FontSizeDescription), Order = 22)]
[Range(1, 10000)]
public int FontSize
{
get => _fontSize;
set
{
_fontSize = value;
ReDraw();
}
}
#endregion
#region ctor
public CotHighAtas()
: base(true)
{
DataSeries[0].IsHidden = true;
DenyToChangePanel = true;
}
#endregion
#region Protected methods
protected override void OnCalculate(int bar, decimal value)
{
if (bar == 0)
{
return;
}
var candle = GetCandle(bar);
var cotBar = new CommitmentOfTradersBar();
decimal cotHigh = 0;
decimal cotLow = 0;
decimal highestPrice = candle.High;
decimal lowestPrice = candle.Low;
decimal totalBuyVolume = 0;
decimal totalSellVolume = 0;
decimal previousPrice = candle.Open;
for (var price = candle.Low; price <= candle.High; price += InstrumentInfo.TickSize)
{
var volumeInfo = candle.GetPriceVolumeInfo(price);
if (volumeInfo == null)
continue;
var buySize = volumeInfo.Ask;
var sellSize = volumeInfo.Bid;
totalBuyVolume += buySize;
totalSellVolume += sellSize;
if (price > highestPrice)
{
highestPrice = price;
cotHigh = 0;
}
else
{
cotHigh += (price > previousPrice) ? buySize : -sellSize; // ????????? ???????? ????
}
if (price < lowestPrice)
{
lowestPrice = price;
cotLow = 0;
}
else
{
cotLow += (price < previousPrice) ? -sellSize : buySize; // ?????????? ??? Low
}
previousPrice = price;
Console.WriteLine($"Price: {price}, CotHigh: {cotHigh}, CotLow: {cotLow}, Buy: {totalBuyVolume}, Sell: {totalSellVolume}");
cotBar.Calculate((double)price, (double)(buySize + sellSize), buySize > sellSize ? Side.Buy : Side.Sell);
}
if (candle.Close == candle.High) cotHigh = 0;
if (candle.Close == candle.Low) cotLow = 0;
AddLabel(new RatioSign(bar, cotHigh > cotLow ? Call : Put,
(double)(cotHigh – cotLow),
cotHigh > cotLow ? (double)highestPrice : (double)lowestPrice));
}
#endregion
#region Private methods
Log($”{bar}: ????: {price}, COT High: {cotHigh}, COT Low: {cotLow}”);
private void AddLabel(RatioSign rs)
{
var bg = System.Drawing.Color.FromArgb(_bgColor.A, _bgColor.R, _bgColor.G, _bgColor.B);
var price = (decimal)rs.Price; // ?????????????? ? double
var labelName = “BAR_” + rs.Bar;
// ??????? ?????????? ????? ? ????? ?? ??????, ???? ??? ??????????
if (Labels.ContainsKey(labelName))
{
Labels.Remove(labelName);
}
var sRatio = rs.Ratio.ToString(“N2”).Replace(“,00”, “”);
// ????????? ????????? ????? ?? ??????
AddText(labelName, sRatio, true, rs.Bar, price, 0, 0,
System.Drawing.Color.FromArgb(_highColor.A, _highColor.R, _highColor.G, _highColor.B),
System.Drawing.Color.Transparent, bg, _fontSize, DrawingText.TextAlign.Center, _fontSize == 0);
}
private void ReDraw()
{
try
{
foreach (var label in Labels)
{
decimal ratio = 0;
// ??????? ????????????? ????? ????? ? ?????
if (decimal.TryParse(label.Value.Text, out var parsedRatio))
{
ratio = parsedRatio;
}
// ????????? ?????????? ?????
label.Value.AutoSize = _fontSize == 0;
label.Value.FontSize = _fontSize;
label.Value.XOffset = 0;
label.Value.FillColor = System.Drawing.Color.FromArgb(_bgColor.A, _bgColor.R, _bgColor.G, _bgColor.B);
// ????????? ????? ?????? ? ??????????? ?? ???????? ratio
if (ratio <= _lowRatio)
{
label.Value.Textcolor = System.Drawing.Color.FromArgb(_lowColor.A, _lowColor.R, _lowColor.G, _lowColor.B);
}
else if (ratio <= _neutralRatio)
{
label.Value.Textcolor = System.Drawing.Color.FromArgb(_neutralColor.A, _neutralColor.R, _neutralColor.G, _neutralColor.B);
}
else
{
label.Value.Textcolor = System.Drawing.Color.FromArgb(_highColor.A, _highColor.R, _highColor.G, _highColor.B);
}
}
}
catch (Exception ex)
{
// ??????????? ?????? (???? ??????????)
Console.WriteLine($"?????? ? ReDraw: {ex.Message}");
}
}
#endregion
}
internal class CommitmentOfTradersBar
{
private double _highPrice = double.MinValue;
private double _lowPrice = double.MaxValue;
public double High { get; private set; }
public double Low { get; private set; }
public double HighPrice => _highPrice;
public double LowPrice => _lowPrice;
public void Calculate(double price, double size, Side side)
{
// ?????? High
if (_highPrice < price || _highPrice == double.MinValue)
{
_highPrice = price;
High = 0;
}
if (side == Side.Buy)
High += size;
else
High -= size;
// ?????? Low
if (_lowPrice > price || _lowPrice == double.MaxValue)
{
_lowPrice = price;
Low = 0;
}
if (side == Side.Buy)
Low -= size;
else
Low += size;
}
}
}