├── .github └── workflows │ ├── dotnet-core.yml │ └── github-actions-demo.yml ├── .gitignore ├── BaseContextHandler.cs ├── ClusterAnalysis ├── AlignedSecurity.DataSourceSecurity.cs ├── AlignedSecurity.cs ├── AlignedSecurityHandler.cs ├── AllTimeTradeStatisticsHandler.cs ├── BaseTradeStatisticsHandler.cs ├── InteractiveSeriesHandler.cs ├── LastContractsTradeStatisticsHandler.cs ├── LastTradeStatisticsHandler.cs ├── MarketPosition.cs ├── SpecifiedQuantityPriceAtTradeHandler.cs ├── TradeStatisticsBarsCountHandler.cs ├── TradeStatisticsBarsHandler.cs ├── TradeStatisticsBarsSumHandler.cs ├── TradeStatisticsBaseExtendedBarsHandler.cs ├── TradeStatisticsBaseExtendedExtremumPriceHandler.cs ├── TradeStatisticsBaseExtremumPriceHandler.cs ├── TradeStatisticsCombine.cs ├── TradeStatisticsEdgeHandler.cs ├── TradeStatisticsExtendedBarsCountHandler.cs ├── TradeStatisticsExtendedBarsCountHandler2.cs ├── TradeStatisticsExtendedBarsHandler.cs ├── TradeStatisticsExtendedBarsHandler2.cs ├── TradeStatisticsExtendedBarsSumHandler.cs ├── TradeStatisticsExtendedBarsSumHandler2.cs ├── TradeStatisticsExtendedExtremumPriceHandler.cs ├── TradeStatisticsExtendedExtremumPriceHandler2.cs ├── TradeStatisticsExtremumPriceHandler.cs ├── TradeStatisticsExtremumValueHandler.cs ├── TradeStatisticsHandler.cs ├── TradeStatisticsLowerEdgeHandler.cs ├── TradeStatisticsPriceValueHandler.cs └── TradeStatisticsUpperEdgeHandler.cs ├── ConstList.cs ├── Constants.cs ├── Cycle ├── AddPositionHandler.cs ├── CycleBoolHandler.cs ├── CycleHandler.cs ├── CycleResultHandler.cs ├── CycleResultsHandler.cs └── CycleValueUpdaterHandler.cs ├── GraphPane ├── InteractiveConstGen.cs ├── InteractiveLineGen.BaseList.cs ├── InteractiveLineGen.ConstList.cs ├── InteractiveLineGen.LineList.cs └── InteractiveLineGen.cs ├── HelperDescriptionAttribute.cs ├── HelperLinkAttribute.cs ├── HelperNameAttribute.cs ├── Indicators ├── ADX.cs ├── AMA.cs ├── Alligator.cs ├── Aroon.cs ├── BarsCountForValuesSumHandler.cs ├── BaseIndicator.cs ├── DoubleStreamAndValuesHandler.cs ├── MACD.cs ├── MAMA.cs ├── Momentum.cs ├── ParabolicSAR.cs ├── SomeIndicators.cs ├── SumForTimeFrameHandler.cs ├── TEMA.cs └── Trix.cs ├── Logging.cs ├── Other ├── EmptyDoubleHandler.cs ├── Heartbeat.cs ├── TEST.cs └── TickTest Handler.cs ├── PortfolioHandlers ├── AgentHandlers.cs ├── Portfolio.Enums.cs └── Portfolio.cs ├── Position ├── HoldSignalForNBars.cs ├── PositionHandlers.cs └── PositionHandlers2.cs ├── ProfitExtensions.cs ├── Properties ├── Resources.resx └── Resources.ru.resx ├── README.md ├── ScriptCommonHandlers.csproj ├── Service ├── ControlMessageHandler.cs ├── EventKindHandler.cs ├── ExportValuesHandler.cs ├── FormatMessageHandler.cs ├── HeartbeatHandler.cs ├── HeartbeatManager.cs ├── ImportBoolValuesHandler.cs ├── ImportDoubleValuesHandler.cs ├── ImportIntValuesHandler.cs ├── ImportValuesHandler.cs ├── InstrumentByName.cs ├── InstrumentByNumber.cs ├── LoadFromGlobalCache2.cs ├── MessageHandler.cs ├── RecalcScheduler.cs ├── SaveToGlobalCache2.cs └── TimestampHandler.cs ├── ShrinkedList.cs ├── TSChannel ├── BoolReceiverHandler.cs ├── ChannelHandler.cs ├── IsReceiverOnline.cs ├── ParameterSenderHandler.cs ├── ReceiverHandler.cs ├── ValueReceiverHandler.cs └── ValueSenderHandler.cs ├── TradeMath ├── AccumHandlers.cs ├── BarNumber.cs ├── BarsConstructorBase.cs ├── BarsConstructorHandler.cs ├── BarsTickDataHandler.cs ├── Compress.cs ├── ConstGen.cs ├── ControlledBoolBreaker.cs ├── ControlledBoolConst.cs ├── ExtremePos.cs ├── FinInfoHandlers.cs ├── Ln.cs ├── Multiply.cs ├── OrderBookPrice.cs ├── OrderBookQty.cs ├── OrderBookTotal.cs ├── RandomHandler.cs ├── ResettableControlledBoolConst.cs ├── ResultForOptimization.cs ├── SecurityHandlers.cs ├── SessionBase.cs ├── Support.cs ├── TextHandler.cs ├── ValueSupportedIndicator.cs └── WeightedAveragePrice.cs ├── ValueUpdaterExecutionOrder.cs └── VolumeAnalysis ├── BuysHandler.cs ├── BuysMinusSellsHandler.cs ├── BuysSellsHandler.cs ├── SellsHandler.cs ├── ValueForPeriodHandler.cs └── VolumeForPeriodHandler.cs /.github/workflows/dotnet-core.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup .NET Core 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: 9.0.x 20 | - name: Restore packages 21 | run: dotnet restore 22 | - name: Pack 23 | run: dotnet pack --configuration Release 24 | - name: Publish 25 | id: publish_nuget 26 | uses: alirezanet/publish-nuget@v3.1.0 27 | with: 28 | PROJECT_FILE_PATH: ScriptCommonHandlers.csproj 29 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 30 | -------------------------------------------------------------------------------- /.github/workflows/github-actions-demo.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Actions Demo 2 | run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 3 | on: [push] 4 | jobs: 5 | Explore-GitHub-Actions: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." 9 | - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" 10 | - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." 11 | - name: Check out repository code 12 | uses: actions/checkout@v4 13 | - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." 14 | - run: echo "🖥️ The workflow is now ready to test your code on the runner." 15 | - name: List files in the repository 16 | run: | 17 | ls ${{ github.workspace }} 18 | - run: echo "🍏 This job's status is ${{ job.status }}." 19 | -------------------------------------------------------------------------------- /ClusterAnalysis/AlignedSecurity.DataSourceSecurity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TSLab.DataSource; 3 | 4 | // ReSharper disable once CheckNamespace 5 | namespace TSLab.Script.Handlers 6 | { 7 | public sealed partial class AlignedSecurity 8 | { 9 | private sealed class DataSourceSecurity : IDataSourceSecurity 10 | { 11 | private readonly IDataSourceSecurity m_source; 12 | 13 | public DataSourceSecurity(IDataSourceSecurity source) 14 | { 15 | m_source = source ?? throw new ArgumentNullException(nameof(source)); 16 | } 17 | 18 | public string ToString(string format, IFormatProvider formatProvider) 19 | { 20 | return m_source + ".Aligned"; 21 | } 22 | 23 | public string Id => m_source.Id; 24 | 25 | public string Name => m_source.Name; 26 | 27 | public string FullName => m_source.FullName; 28 | 29 | public string Comment => m_source.Comment; 30 | 31 | public string Currency => m_source.Currency; 32 | 33 | public IDataSourceTradePlace TradePlace => m_source.TradePlace; 34 | 35 | public string DSName => m_source.DSName + ".Aligned"; 36 | 37 | public string ProviderName => m_source.ProviderName + ".Aligned"; 38 | 39 | public double LotSize => m_source.LotSize; 40 | 41 | public double LotTick => m_source.LotTick; 42 | 43 | public double Margin => m_source.Margin; 44 | 45 | public int Decimals => m_source.Decimals; 46 | 47 | public int BalanceDecimals => m_source.BalanceDecimals; 48 | 49 | public int BalancePriceDecimals => m_source.BalancePriceDecimals; 50 | 51 | public double Tick => m_source.Tick; 52 | 53 | public double GetTick(double price) 54 | { 55 | throw new NotSupportedException(); 56 | } 57 | 58 | public bool Expired => throw new NotSupportedException(); 59 | 60 | public bool IsMoney => throw new NotSupportedException(); 61 | 62 | public ActiveType ActiveType => throw new NotSupportedException(); 63 | 64 | public bool IsOption => throw new NotSupportedException(); 65 | 66 | public IDataSourceSecurity BaseSecurity => throw new NotSupportedException(); 67 | 68 | public CalcSourceInfo CalcSecurity { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } 69 | 70 | public double Strike => throw new NotSupportedException(); 71 | 72 | public DateTime ExpirationDate => throw new NotSupportedException(); 73 | 74 | public double ReducedPrice(double price) => m_source.ReducedPrice(price); 75 | 76 | public double ReducedPrice(double price, CalcSourceParams? calcParams) 77 | { 78 | return m_source.ReducedPrice(price, calcParams); 79 | } 80 | 81 | public double CalculatePnL(double entryPrice, double exitPrice, double lots) 82 | { 83 | return m_source.CalculatePnL(entryPrice, exitPrice, lots); 84 | } 85 | 86 | public double CalculatePnL(double entryPrice, double exitPrice, double lots, CalcSourceParams? calcParams) 87 | { 88 | return m_source.CalculatePnL(entryPrice, exitPrice, lots, calcParams); 89 | } 90 | 91 | public double GetCostPrice(CalcSourceParams? calcParams) 92 | { 93 | return m_source.GetCostPrice(calcParams); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ClusterAnalysis/AlignedSecurityHandler.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using TSLab.DataSource; 3 | using TSLab.Script.Handlers.Options; 4 | 5 | namespace TSLab.Script.Handlers 6 | { 7 | // TODO: английское описание 8 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 9 | [HelperName("Aligned instrument", Language = Constants.En)] 10 | [HelperName("Выровненный инструмент", Language = Constants.Ru)] 11 | [InputsCount(1)] 12 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 13 | [OutputsCount(1)] 14 | [OutputType(TemplateTypes.SECURITY)] 15 | [Description("Блок 'Выровненный инструмент' обеспечивает отображение гистограмм одинаковой ширины вне зависимости от фактического количества свечей в графике.")] 16 | [HelperDescription("", Constants.En)] 17 | public sealed class AlignedSecurityHandler : IAlignedSecurityHandler 18 | { 19 | /// 20 | /// \~english Timeframe (integer value in units of parameter 'Timeframe units') 21 | /// \~russian Интервал (целое число в единицах параметра 'База интервала') 22 | /// 23 | [HelperName("Timeframe", Constants.En)] 24 | [HelperName("Интервал", Constants.Ru)] 25 | [Description("Интервал (целое число в единицах параметра 'База интервала')")] 26 | [HelperDescription("Timeframe (integer value in units of parameter 'Timeframe units')", Constants.En)] 27 | [HandlerParameter(true, "1", Min = "1", Max = "365", Step = "1")] 28 | public int TimeFrame { get; set; } 29 | 30 | /// 31 | /// \~english Timeframe units (second, minute, hour, day) 32 | /// \~russian База интервала (секунды, минуты, часы, дни) 33 | /// 34 | [HelperName("Timeframe units", Constants.En)] 35 | [HelperName("База интервала", Constants.Ru)] 36 | [Description("База интервала (секунды, минуты, часы, дни)")] 37 | [HelperDescription("Timeframe units (second, minute, hour, day)", Constants.En)] 38 | [HandlerParameter(true, nameof(TimeFrameUnit.Hour))] 39 | public TimeFrameUnit TimeFrameUnit { get; set; } 40 | 41 | public ISecurity Execute(ISecurity security) 42 | { 43 | var timeFrame = TimeFrameFactory.Create(TimeFrame, TimeFrameUnit); 44 | return new AlignedSecurity(security, timeFrame); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ClusterAnalysis/AllTimeTradeStatisticsHandler.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using TSLab.Script.Handlers.Options; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | // TODO: английское описание 7 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 8 | [HelperName("All Time Trade Statistics", Language = Constants.En)] 9 | [HelperName("Торговая статистика за всё время", Language = Constants.Ru)] 10 | [InputsCount(1)] 11 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 12 | [OutputsCount(1)] 13 | [OutputType(TemplateTypes.TRADE_STATISTICS)] 14 | [Description("Блок 'Торговая статистика за всё время' создает гистограмму на основе всего доступного временного интервала. " + 15 | "[br]Гистограмма может быть построена на количестве сделок, объеме торгов, количестве покупок, количестве продаж, разнице количества покупок и продаж и относительной разнице количества покупок и продаж, % (см. параметр 'Вид').")] 16 | [HelperDescription("", Constants.En)] 17 | public sealed class AllTimeTradeStatisticsHandler : BaseTradeStatisticsHandler, IAllTimeTradeStatisticsHandler 18 | { 19 | /// 20 | /// \~english A width of a hystogram relative to a width of a chart pane. 21 | /// \~russian Ширина гистограммы в процентах относительно ширины панели графика. 22 | /// 23 | [HelperName("Width, %", Constants.En)] 24 | [HelperName("Ширина, %", Constants.Ru)] 25 | [Description("Ширина гистограммы в процентах относительно ширины панели графика.")] 26 | [HelperDescription("A width of a hystogram relative to a width of a chart pane.", Constants.En)] 27 | [HandlerParameter(true, "10", Min = "1", Max = "100", Step = "1", EditorMin = "1", EditorMax = "100")] 28 | public override double WidthPercent { get; set; } 29 | 30 | protected override ITradeStatisticsWithKind InternalExecute(ISecurity security) 31 | { 32 | var runTime = Context.Runtime; 33 | var id = runTime != null ? string.Join(".", runTime.TradeName, runTime.IsAgentMode, VariableId) : VariableId; 34 | var descriptionId = security.SecurityDescription?.Id ?? security.Symbol; 35 | var dsName = security.SecurityDescription?.DSName; 36 | if (dsName != null) 37 | descriptionId = $"{descriptionId}-{dsName}"; 38 | var stateId = string.Join(".", descriptionId, security.Interval, security.IsAligned, CombinePricesCount); 39 | var tradeStatistics = Context.GetTradeStatistics(stateId, () => TradeStatisticsCache.Instance.GetAllTimeTradeStatistics(id, stateId, GetTradeHistogramsCache(security))); 40 | return new AllTimeTradeStatisticsWithKind(tradeStatistics, Kind, WidthPercent); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ClusterAnalysis/BaseTradeStatisticsHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | //[HandlerCategory(HandlerCategories.ClusterAnalysis)] 10 | // Не стоит навешивать на абстрактные классы атрибуты категорий и описания входов/выходов. Это снижает гибкость управления в перспективе. 11 | public abstract class BaseTradeStatisticsHandler : IBaseTradeStatisticsHandler 12 | where TTradeStatisticsWithKind : IBaseTradeStatisticsWithKind 13 | { 14 | public string VariableId { get; set; } = string.Empty; 15 | 16 | public IContext Context { get; set; } 17 | 18 | /// 19 | /// \~english How many price steps should be grouped together. 20 | /// \~russian Осуществление выбора шага цены, используемого для группировки цен. 21 | /// 22 | [HelperName("Combine price steps", Constants.En)] 23 | [HelperName("Объединять шаги цены", Constants.Ru)] 24 | [Description("Осуществление выбора шага цены, используемого для группировки цен.")] 25 | [HelperDescription("How many price steps should be grouped together.", Constants.En)] 26 | [HandlerParameter(true, "1", Min = "1", Max = "10", Step = "1", EditorMin = "1")] 27 | public int CombinePricesCount { get; set; } 28 | 29 | /// 30 | /// \~english Kind of a trade statistics (trades count, trade volume, buy count, sell count, buy and sell difference, relative buy and sell difference). 31 | /// \~russian Вид торговой статистики (количество сделок, объем торгов, количество покупок, количество продаж, разница количества покупок и продаж, относительная разница количества покупок и продаж). 32 | /// 33 | [HelperName("Kind", Constants.En)] 34 | [HelperName("Вид", Constants.Ru)] 35 | [Description("Вид торговой статистики (количество сделок, объем торгов, количество покупок, количество продаж, разница количества покупок и продаж, относительная разница количества покупок и продаж).")] 36 | [HelperDescription("Kind of a trade statistics (trades count, trade volume, buy count, sell count, buy and sell difference, relative buy and sell difference).", Constants.En)] 37 | [HandlerParameter(true, nameof(TradeStatisticsKind.TradesCount))] 38 | public TradeStatisticsKind Kind { get; set; } 39 | 40 | /// 41 | /// \~english A width of a hystogram relative to a width of a chart pane. 42 | /// \~russian Ширина гистограммы в процентах относительно ширины панели графика. 43 | /// 44 | [HelperName("Width, %", Constants.En)] 45 | [HelperName("Ширина, %", Constants.Ru)] 46 | [Description("Ширина гистограммы в процентах относительно ширины панели графика.")] 47 | [HelperDescription("A width of a hystogram relative to a width of a chart pane.", Constants.En)] 48 | [HandlerParameter(true, "100", Min = "1", Max = "100", Step = "1", EditorMin = "1", EditorMax = "100")] 49 | public virtual double WidthPercent { get; set; } 50 | 51 | public TTradeStatisticsWithKind Execute(ISecurity security) 52 | { 53 | if (security == null) 54 | throw new ArgumentNullException(nameof(security)); 55 | var sw = Stopwatch.StartNew(); 56 | try 57 | { 58 | var decompressedSecurity = Context.Runtime.Securities.First( 59 | item => item.SecurityDescription.Id == security.SecurityDescription.Id 60 | && item.SecurityDescription.DSName == security.SecurityDescription.DSName); 61 | return InternalExecute(decompressedSecurity); 62 | } 63 | finally 64 | { 65 | if (sw.Elapsed.TotalSeconds > 5) 66 | Context?.Log($"Time elapsed {this.GetType().Name}: {sw.Elapsed}", MessageType.Debug); 67 | } 68 | } 69 | 70 | protected abstract TTradeStatisticsWithKind InternalExecute(ISecurity security); 71 | 72 | protected ITradeHistogramsCache GetTradeHistogramsCache(ISecurity security) 73 | { 74 | var result = TradeHistogramsCaches.Instance.GetTradeHistogramsCache(Context, security, CombinePricesCount); 75 | return result; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ClusterAnalysis/InteractiveSeriesHandler.cs: -------------------------------------------------------------------------------- 1 | #if DEBUG 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | 6 | using TSLab.Script.CanvasPane; 7 | using TSLab.Script.Handlers.Options; 8 | 9 | namespace TSLab.Script.Handlers 10 | { 11 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 12 | [HelperName("InteractiveSeriesHandler", Language = Constants.En)] 13 | [HelperName("InteractiveSeriesHandler", Language = Constants.Ru)] 14 | [InputsCount(1)] 15 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 16 | [OutputsCount(1)] 17 | [OutputType(TemplateTypes.INTERACTIVESPLINE)] 18 | [Description("БЕЗ ОПИСАНИЯ (кубик виден только в девелоперской версии)")] 19 | [HelperDescription("БЕЗ ОПИСАНИЯ (кубик виден только в девелоперской версии)", Constants.En)] 20 | #if !DEBUG 21 | [HandlerInvisible] 22 | #endif 23 | public sealed class InteractiveSeriesHandler : IOneSourceHandler, IStreamHandler, ISecurityInputs 24 | { 25 | public InteractiveSeries Execute(ISecurity security) 26 | { 27 | var interactiveObjects = new List(); 28 | for (byte i = 0; i < 31; i++) 29 | { 30 | var j = (byte)(i << 3); 31 | var interactivePointActive = new InteractivePointActive(i, i) 32 | { 33 | BackColor = new Color(j, 0, 0), 34 | ForeColor = new Color(0, j, 0), 35 | 36 | IsActive = true, 37 | Label = i.ToString(), 38 | Color = new AlphaColor(255, j, 0, 0), 39 | DateTime = DateTime.UtcNow.AddDays(1), 40 | 41 | ValueXBackColor = new AlphaColor(255, j, 0, 0), 42 | ValueXForeColor = new AlphaColor(255, 0, j, 0), 43 | 44 | ValueYBackColor = new AlphaColor(255, 0, j, 0), 45 | ValueYForeColor = new AlphaColor(255, 0, 0, j), 46 | 47 | DateTimeBackColor = new AlphaColor(255, 0, 0, j), 48 | DateTimeForeColor = new AlphaColor(255, j, 0, 0), 49 | }; 50 | interactiveObjects.Add(new InteractiveObject { Anchor = interactivePointActive }); 51 | } 52 | return new InteractiveSeries(interactiveObjects); 53 | } 54 | } 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /ClusterAnalysis/LastContractsTradeStatisticsHandler.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using TSLab.Script.Handlers.Options; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | // TODO: английское описание 7 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 8 | [HelperName("Last Contracts Trade Statistics", Language = Constants.En)] 9 | [HelperName("Торговая статистика последних контрактов", Language = Constants.Ru)] 10 | [InputsCount(1)] 11 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 12 | [OutputsCount(1)] 13 | [OutputType(TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 14 | [Description("Блок 'Торговая статистика последних контрактов' создает гистограмму за указанное количество последних контрактов.")] 15 | [HelperDescription("", Constants.En)] 16 | public sealed class LastContractsTradeStatisticsHandler : BaseTradeStatisticsHandler, ILastContractsTradeStatisticsHandler 17 | { 18 | /// 19 | /// \~english A parameter to set contracts count to be used for trade statistics. 20 | /// \~russian Осуществляет выбор количества контрактов, за которые должна отображаться торговая статистика. 21 | /// 22 | [HelperName("Contracts count", Constants.En)] 23 | [HelperName("Количество контрактов", Constants.Ru)] 24 | [Description("Осуществляет выбор количества контрактов, за которые должна отображаться торговая статистика.")] 25 | [HelperDescription("A parameter to set contracts count to be used for trade statistics.", Constants.En)] 26 | [HandlerParameter(true, "10000", Min = "10000", Max = "1000000", Step = "10000", EditorMin = "1")] 27 | public int ContractsCount { get; set; } 28 | 29 | protected override ILastContractsTradeStatisticsWithKind InternalExecute(ISecurity security) 30 | { 31 | var runTime = Context.Runtime; 32 | var id = runTime != null ? string.Join(".", runTime.TradeName, runTime.IsAgentMode, VariableId) : VariableId; 33 | var descriptionId = security.SecurityDescription?.Id ?? security.Symbol; 34 | var dsName = security.SecurityDescription?.DSName; 35 | if (dsName != null) 36 | descriptionId = $"{descriptionId}-{dsName}"; 37 | var stateId = string.Join(".", descriptionId, security.Interval, security.IsAligned, CombinePricesCount, ContractsCount); 38 | var tradeStatistics = Context.GetLastContractsTradeStatistics(stateId, () => new LastContractsTradeStatistics(id, stateId, GetTradeHistogramsCache(security), ContractsCount)); 39 | return new LastContractsTradeStatisticsWithKind(tradeStatistics, Kind, WidthPercent); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ClusterAnalysis/LastTradeStatisticsHandler.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using TSLab.DataSource; 3 | using TSLab.Script.Handlers.Options; 4 | 5 | namespace TSLab.Script.Handlers 6 | { 7 | // TODO: английское описание 8 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 9 | [HelperName("Last Trade Statistics", Language = Constants.En)] 10 | [HelperName("Последняя торговая статистика", Language = Constants.Ru)] 11 | [InputsCount(1)] 12 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 13 | [OutputsCount(1)] 14 | [OutputType(TemplateTypes.TRADE_STATISTICS)] 15 | [Description("Блок 'Последняя торговая статистика' создает гистограмму за указанный временной интервал.")] 16 | [HelperDescription("", Constants.En)] 17 | public sealed class LastTradeStatisticsHandler : BaseTradeStatisticsHandler, ITradeStatisticsHandler 18 | { 19 | [HandlerParameter(true, nameof(TimeFrameKind.FromMidnightToNow))] 20 | public TimeFrameKind TimeFrameKind { get; set; } 21 | 22 | /// 23 | /// \~english Timeframe (integer value in units of parameter 'Timeframe units') 24 | /// \~russian Интервал (целое число в единицах параметра 'База интервала') 25 | /// 26 | [HelperName("Timeframe", Constants.En)] 27 | [HelperName("Интервал", Constants.Ru)] 28 | [Description("Интервал (целое число в единицах параметра 'База интервала')")] 29 | [HelperDescription("Timeframe (integer value in units of parameter 'Timeframe units')", Constants.En)] 30 | [HandlerParameter(true, "1", Min = "1", Max = "365", Step = "1", EditorMin = "1")] 31 | public int TimeFrame { get; set; } 32 | 33 | /// 34 | /// \~english Timeframe units (second, minute, hour, day) 35 | /// \~russian База интервала (секунды, минуты, часы, дни) 36 | /// 37 | [HelperName("Timeframe units", Constants.En)] 38 | [HelperName("База интервала", Constants.Ru)] 39 | [Description("База интервала (секунды, минуты, часы, дни)")] 40 | [HelperDescription("Timeframe units (second, minute, hour, day)", Constants.En)] 41 | [HandlerParameter(true, nameof(TimeFrameUnit.Hour))] 42 | public TimeFrameUnit TimeFrameUnit { get; set; } 43 | 44 | [HandlerParameter(true, "0", Min = "0", Max = "365", Step = "1", EditorMin = "0")] 45 | public int TimeFrameShift { get; set; } 46 | 47 | [HandlerParameter(true, nameof(TimeFrameUnit.Hour))] 48 | public TimeFrameUnit TimeFrameShiftUnit { get; set; } 49 | 50 | protected override ITradeStatisticsWithKind InternalExecute(ISecurity security) 51 | { 52 | var interval = TimeFrameFactory.GetInterval(TimeFrame, TimeFrameUnit); 53 | var intervalShift = TimeFrameShift > 0 ? TimeFrameFactory.GetInterval(TimeFrameShift, TimeFrameShiftUnit) : null; 54 | 55 | var runTime = Context.Runtime; 56 | var id = runTime != null 57 | ? string.Join(".", runTime.TradeName, runTime.IsAgentMode, VariableId) 58 | : VariableId; 59 | 60 | var descriptionId = security.SecurityDescription?.Id ?? security.Symbol; 61 | var dsName = security.SecurityDescription?.DSName; 62 | if (dsName != null) 63 | descriptionId = $"{descriptionId}-{dsName}"; 64 | var stateId = string.Join(".", descriptionId, security.Interval, security.IsAligned, CombinePricesCount, 65 | TimeFrameKind, TimeFrame, TimeFrameUnit, TimeFrameShift, TimeFrameShiftUnit); 66 | 67 | var tradeStatistics = Context.GetTradeStatistics(stateId, 68 | () => new LastTradeStatistics(id, stateId, GetTradeHistogramsCache(security), TimeFrameKind, 69 | TimeFrameUnit, TimeFrameShiftUnit, interval, intervalShift)); 70 | 71 | return new TradeStatisticsWithKind(tradeStatistics, Kind, WidthPercent); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ClusterAnalysis/SpecifiedQuantityPriceAtTradeHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using TSLab.DataSource; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 10 | public sealed class SpecifiedQuantityPriceAtTradeHandler : ISpecifiedQuantityPriceAtTradeHandler 11 | { 12 | public IContext Context { get; set; } 13 | 14 | [HandlerParameter(true, "0", Min = "0", Max = "2147483647", Step = "1", EditorMin = "0", EditorMax = "2147483647")] 15 | public double Quantity { get; set; } 16 | 17 | [HandlerParameter(true, nameof(SpecifiedTradeDirection.Any))] 18 | public SpecifiedTradeDirection Direction { get; set; } 19 | 20 | public IList Execute(ISecurity security) 21 | { 22 | Func isValidTradeFunc; 23 | if (Direction == SpecifiedTradeDirection.Any) 24 | isValidTradeFunc = IsValidAnyTrade; 25 | else if (Direction == SpecifiedTradeDirection.Buy) 26 | isValidTradeFunc = IsValidBuyTrade; 27 | else if (Direction == SpecifiedTradeDirection.Sell) 28 | isValidTradeFunc = IsValidSellTrade; 29 | else 30 | throw new InvalidEnumArgumentException(nameof(Direction), (int)Direction, typeof(SpecifiedTradeDirection)); 31 | 32 | var barsCount = Context.BarsCount; 33 | var results = Context.GetArray(barsCount); 34 | var tradesCache = Context.GetTradesCache(security); 35 | var price = 0D; 36 | 37 | for (var i = 0; i < barsCount; i++) 38 | { 39 | var trade = tradesCache.GetTrades(i).LastOrDefault(isValidTradeFunc); 40 | if (trade != null) 41 | price = trade.Price; 42 | 43 | results[i] = price; 44 | } 45 | return results; 46 | } 47 | 48 | private bool IsValidAnyTrade(ITrade trade) 49 | { 50 | return trade.Quantity > Quantity; 51 | } 52 | 53 | private bool IsValidBuyTrade(ITrade trade) 54 | { 55 | return trade.Direction == TradeDirection.Buy && trade.Quantity > Quantity; 56 | } 57 | 58 | private bool IsValidSellTrade(ITrade trade) 59 | { 60 | return trade.Direction == TradeDirection.Sell && trade.Quantity > Quantity; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsBarsCountHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | // TODO: английское описание 10 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 11 | [HelperName("Trade Statistics Strings Count", Language = Constants.En)] 12 | [HelperName("Количество строк торговой статистики", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Блок 'Количество строк торговой статистики' выдает количество строк торговой статистики, соответствующее выбранному фильтру.")] 18 | [HelperDescription("", Constants.En)] 19 | public sealed class TradeStatisticsBarsCountHandler : TradeStatisticsBarsHandler, ITradeStatisticsBarsCountHandler 20 | { 21 | protected override double GetResult(IBaseTradeStatisticsWithKind tradeStatistics, IEnumerable bars) 22 | { 23 | return bars.Count(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsBarsSumHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | // TODO: английское описание 10 | // TODO: удачно ли здесь использовать слово 'string' как перевод слова 'строка'? 11 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 12 | [HelperName("Trade Statistics Strings Sum", Language = Constants.En)] 13 | [HelperName("Сумма строк торговой статистики", Language = Constants.Ru)] 14 | [InputsCount(1)] 15 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 16 | [OutputsCount(1)] 17 | [OutputType(TemplateTypes.DOUBLE)] 18 | [Description("Блок 'Сумма строк торговой статистики' выдает значение, основанное на сумме значений строк торговой статистики.")] 19 | [HelperDescription("", Constants.En)] 20 | public sealed class TradeStatisticsBarsSumHandler : TradeStatisticsBarsHandler, ITradeStatisticsBarsCountHandler 21 | { 22 | protected override double GetResult(IBaseTradeStatisticsWithKind tradeStatistics, IEnumerable bars) 23 | { 24 | return bars.Sum(item => tradeStatistics.GetValue(item)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsBaseExtremumPriceHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Globalization; 5 | using System.Linq; 6 | using TSLab.Script.Handlers.Options; 7 | 8 | // ReSharper disable once CheckNamespace 9 | namespace TSLab.Script.Handlers 10 | { 11 | //[HandlerCategory(HandlerCategories.ClusterAnalysis)] 12 | // Не стоит навешивать на абстрактные классы атрибуты категорий и описания входов/выходов. Это снижает гибкость управления в перспективе. 13 | 14 | /// 15 | /// Базовый класс для расчета экстремумов торговой стаистистики. 16 | /// На вход подается Торговая Статистика, на выход идут числа. 17 | /// 18 | public abstract class TradeStatisticsBaseExtremumPriceHandler : ITradeStatisticsBaseExtremumPriceHandler 19 | { 20 | protected sealed class Extremum 21 | { 22 | public Extremum(ITradeHistogramBar bar, double value, double price) 23 | { 24 | Bar = bar; 25 | Value = value; 26 | Price = price; 27 | } 28 | 29 | public ITradeHistogramBar Bar { get; } 30 | public double Value { get; } 31 | public double Price { get; } 32 | } 33 | 34 | public string VariableId { get; set; } 35 | 36 | public IContext Context { get; set; } 37 | 38 | /// 39 | /// \~english Extremum kind (minimum, maximum). 40 | /// \~russian Вид экстремума (минимум, максимум). 41 | /// 42 | [HelperName("Extremum kind", Constants.En)] 43 | [HelperName("Вид экстремума", Constants.Ru)] 44 | [Description("Вид экстремума (минимум, максимум)")] 45 | [HelperDescription("Extremum kind (minimum, maximum).", Constants.En)] 46 | [HandlerParameter(true, nameof(ExtremumPriceMode.Minimum))] 47 | public ExtremumPriceMode PriceMode { get; set; } 48 | 49 | [HelperName("Min Bar, %", Constants.En)] 50 | [HelperName("Минимальный бар, %", Constants.Ru)] 51 | [HandlerParameter(true, "0", Min = "0", Max = "100", Step = "1", EditorMin = "0")] 52 | public double MinBarPct { get; set; } 53 | 54 | [HelperName("Max Bar, %", Constants.En)] 55 | [HelperName("максимальный бар, %", Constants.Ru)] 56 | [HandlerParameter(true, "100", Min = "0", Max = "100", Step = "1", EditorMin = "0")] 57 | public double MaxBarPct { get; set; } = 100; 58 | 59 | public abstract IList Execute(IBaseTradeStatisticsWithKind tradeStatistics); 60 | 61 | protected Extremum GetExtremum(IBaseTradeStatisticsWithKind tradeStatistics, 62 | IAggregatedHistogramBarsProvider aggregatedHistogramBarsProvider, int barIndex, 63 | ref double lastPrice) 64 | { 65 | var bars = aggregatedHistogramBarsProvider.GetAggregatedHistogramBars(barIndex); 66 | if (bars.Count == 0) 67 | return new Extremum(null, double.NaN, lastPrice); 68 | 69 | if (bars.Count == 1) 70 | { 71 | var bar = bars[0]; 72 | return new Extremum(bar, Math.Abs(tradeStatistics.GetValue(bar)), lastPrice = bar.AveragePrice); 73 | } 74 | 75 | var minBar = (int)(bars.Count * MinBarPct / 100.0); 76 | var maxBar = (int)(bars.Count * MaxBarPct / 100.0); 77 | var count = maxBar - minBar; 78 | 79 | var reverse = PriceMode == ExtremumPriceMode.Maximum; 80 | var start = reverse ? bars.Count - minBar - 1 : minBar; 81 | var step = reverse ? -1 : 1; 82 | 83 | var extremumBar = bars[start]; 84 | var extremumValue = Math.Abs(tradeStatistics.GetValue(extremumBar)); 85 | 86 | for (int i = start, k = 0; k++ < count - 1;) 87 | { 88 | var bar = bars[i += step]; 89 | var value = Math.Abs(tradeStatistics.GetValue(bar)); 90 | if (extremumValue >= value) 91 | continue; 92 | extremumBar = bar; 93 | extremumValue = value; 94 | } 95 | 96 | return new Extremum(extremumBar, extremumValue, lastPrice = extremumBar.AveragePrice); 97 | } 98 | 99 | protected virtual string GetParametersStateId() 100 | { 101 | return string.Join(".", PriceMode.ToString(), MinBarPct.ToString(CultureInfo.InvariantCulture), 102 | MaxBarPct.ToString(CultureInfo.InvariantCulture)); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsCombine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using TSLab.DataSource; 7 | using TSLab.Script.Handlers.Options; 8 | 9 | namespace TSLab.Script.Handlers.ClusterAnalysis 10 | { 11 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 12 | [HelperName("Stacked Trading Statistics", Language = Constants.En)] 13 | [HelperName("Сложенная Торговая статистика", Language = Constants.Ru)] 14 | [InputsCount(1)] 15 | [Input(0, TemplateTypes.TRADE_STATISTICS)] 16 | [OutputsCount(1)] 17 | [OutputType(TemplateTypes.TRADE_STATISTICS)] 18 | [Description("Блок 'Сложенная Торговая статистика' складывает последние N, поданных на вход.")] 19 | [HelperDescription("", Constants.En)] 20 | public sealed class TradeStatisticsCombineHandler : BasePeriodIndicatorHandler, 21 | IOneSourceHandler, 22 | IStreamHandler, 23 | INeedVariableId, 24 | IContextUses, 25 | ITradeStatisticsReturns 26 | { 27 | public ITradeStatisticsWithKind Execute(ITradeStatisticsWithKind input) 28 | { 29 | if (input == null) 30 | throw new ArgumentNullException(nameof(input)); 31 | 32 | var runTime = Context.Runtime; 33 | var id = runTime != null 34 | ? string.Join(".", runTime.TradeName, runTime.IsAgentMode, VariableId) 35 | : VariableId; 36 | var stateId = string.Join(".", input.StateId, Period); 37 | var tradeStatistics = Context.GetTradeStatistics(stateId, 38 | () => new TradeStatisticsCombine(id, stateId, Period, input)); 39 | return new TradeStatisticsWithKind(tradeStatistics, input.Kind, input.WidthPercent); 40 | } 41 | 42 | public string VariableId { get; set; } 43 | 44 | public IContext Context { get; set; } 45 | } 46 | 47 | public sealed class TradeStatisticsCombine : BaseTradeStatistics, ITradeStatistics 48 | { 49 | private readonly ITradeStatisticsWithKind m_input; 50 | 51 | public TradeStatisticsCombine(string id, string stateId, int period, ITradeStatisticsWithKind input) 52 | : base(id, stateId, new TradeHistogramSettings(input.TradeHistogramsCache, 53 | TimeFrameKind.FromMidnightToNow, input.GetTimeFrameUnit(), new Interval(period, DataIntervals.MINUTE))) 54 | { 55 | m_input = input; 56 | CalculateHistograms(); 57 | } 58 | 59 | public override bool HasStaticTimeline => m_input.HasStaticTimeline; 60 | 61 | protected override IReadOnlyList CalculateHistograms() 62 | { 63 | var histograms = new List(); 64 | 65 | var queue = new Queue(); 66 | var period = m_histogramSettings.Interval.Value; 67 | foreach (var histogram in m_input.GetHistograms()) 68 | { 69 | if (queue.Count >= period) 70 | queue.Dequeue(); 71 | queue.Enqueue(histogram); 72 | 73 | histograms.Add(new CombinedHistogram(m_histogramSettings, queue.First(), queue.Last())); 74 | } 75 | 76 | Parallel.ForEach(histograms.Where(item => !item.IsCalculated), (item) => item.Recalculate()); 77 | 78 | m_histograms = histograms; 79 | return histograms; 80 | } 81 | 82 | public TimeSpan TimeFrameShift => m_input.TimeFrameShift; 83 | 84 | public TimeFrameUnit GetTimeFrameUnit() => m_input.GetTimeFrameUnit(); 85 | 86 | public override ITradeHistogram GetLastHistogram() 87 | { 88 | return m_histograms.LastOrDefault(); 89 | } 90 | } 91 | 92 | public class CombinedHistogram : BaseRefreshableTradeHistogram 93 | { 94 | public override int RealFirstBarIndex { get; } 95 | 96 | internal CombinedHistogram(TradeHistogramSettings histogramSettings, ITradeHistogram first, ITradeHistogram last) 97 | : base(histogramSettings) 98 | { 99 | RealFirstBarIndex = first.FirstBarIndex; 100 | FirstBarIndex = last.FirstBarIndex; 101 | LastBarIndex = last.LastBarIndex; 102 | LowDate = first.LowDate; 103 | HighDate = last.HighDate; 104 | } 105 | 106 | protected override IReadOnlyList GetCachedTradeHistograms() 107 | { 108 | return TradeHistogramsCache.GetHistograms(RealFirstBarIndex, LastBarIndex); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsExtendedBarsCountHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | // TODO: английское описание 10 | // TODO: удачно ли здесь использовать слово 'string' как перевод слова 'строка'? 11 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 12 | [HelperName("Trade Statistics Extended Strings Count 1", Language = Constants.En)] 13 | [HelperName("Расширенное количество строк торговой статистики 1", Language = Constants.Ru)] 14 | [InputsCount(1)] 15 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 16 | [OutputsCount(1)] 17 | [OutputType(TemplateTypes.DOUBLE)] 18 | [Description("Блок 'Расширенное количество строк торговой статистики 1' выдает количество строк торговой статистики, соответствующее выбранному фильтру.")] 19 | [HelperDescription("", Constants.En)] 20 | public sealed class TradeStatisticsExtendedBarsCountHandler : TradeStatisticsExtendedBarsHandler, ITradeStatisticsExtendedBarsCountHandler 21 | { 22 | protected override double GetResult(IBaseTradeStatisticsWithKind tradeStatistics, IEnumerable bars) 23 | { 24 | return bars.Count(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsExtendedBarsCountHandler2.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | // TODO: английское описание 10 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 11 | [HelperName("Trade Statistics Extended Strings Count 2", Language = Constants.En)] 12 | [HelperName("Расширенное количество строк торговой статистики 2", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Блок 'Расширенное количество строк торговой статистики 2' выдает количество строк торговой статистики, соответствующее выбранному фильтру.")] 18 | [HelperDescription("", Constants.En)] 19 | public sealed class TradeStatisticsExtendedBarsCountHandler2 : TradeStatisticsExtendedBarsHandler2, ITradeStatisticsExtendedBarsCountHandler2 20 | { 21 | protected override double GetResult(IBaseTradeStatisticsWithKind tradeStatistics, IEnumerable bars) 22 | { 23 | return bars.Count(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsExtendedBarsHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | 4 | using TSLab.Script.Handlers.Options; 5 | 6 | namespace TSLab.Script.Handlers 7 | { 8 | // Не стоит навешивать на абстрактные классы атрибуты категорий и описания входов/выходов 9 | public abstract class TradeStatisticsExtendedBarsHandler : TradeStatisticsBaseExtendedBarsHandler, ITradeStatisticsExtendedBarsHandler 10 | { 11 | [HandlerParameter(true, NotOptimized = true)] 12 | public bool UseTrimTradesCount { get; set; } 13 | 14 | [HandlerParameter(true, "0", Min = "0", Max = "2147483647", Step = "1", EditorMin = "0")] 15 | public int TrimTradesCount { get; set; } 16 | 17 | [HandlerParameter(true, NotOptimized = true)] 18 | public bool UseTrimQuantity { get; set; } 19 | 20 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 21 | public double TrimQuantity { get; set; } 22 | 23 | [HandlerParameter(true, NotOptimized = true)] 24 | public bool UseTrimAskQuantity { get; set; } 25 | 26 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 27 | public double TrimAskQuantity { get; set; } 28 | 29 | [HandlerParameter(true, NotOptimized = true)] 30 | public bool UseTrimBidQuantity { get; set; } 31 | 32 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 33 | public double TrimBidQuantity { get; set; } 34 | 35 | [HandlerParameter(true, NotOptimized = true)] 36 | public bool UseTrimDeltaAskBidQuantity { get; set; } 37 | 38 | [HandlerParameter(true, "0", Min = "-999999999999999", Max = "999999999999999", Step = "1")] 39 | public double TrimDeltaAskBidQuantity { get; set; } 40 | 41 | [HandlerParameter(true, "false", NotOptimized = true)] 42 | public bool UseTrimRelativeDeltaAskBidQuantityPercent { get; set; } 43 | 44 | [HandlerParameter(true, "0", Min = "-100", Max = "100", Step = "1")] 45 | public double TrimRelativeDeltaAskBidQuantityPercent { get; set; } 46 | 47 | /// 48 | /// \~english Comparison operator for trimming (greater, greater or equal, less, less or equal, equal, not equal). 49 | /// \~russian Оператор сравнения для формирования отсечек (больше, больше или равно, меньше, меньше или равно, равно, не равно). 50 | /// 51 | [HelperName("Comparison operator", Constants.En)] 52 | [HelperName("Режим сравнения отсечки", Constants.Ru)] 53 | [Description("Оператор сравнения для формирования отсечек (больше, больше или равно, меньше, меньше или равно, равно, не равно).")] 54 | [HelperDescription("Comparison operator for trimming (greater, greater or equal, less, less or equal, equal, not equal).", Constants.En)] 55 | [HandlerParameter(true, nameof(ComparisonMode.GreaterOrEqual))] 56 | public ComparisonMode TrimComparisonMode { get; set; } 57 | 58 | public IList Execute(IBaseTradeStatisticsWithKind tradeStatistics) 59 | { 60 | return Execute( 61 | tradeStatistics, 62 | new TrimContext(UseTrimTradesCount, TrimTradesCount, TrimComparisonMode), 63 | new TrimContext(UseTrimQuantity, TrimQuantity, TrimComparisonMode), 64 | new TrimContext(UseTrimAskQuantity, TrimAskQuantity, TrimComparisonMode), 65 | new TrimContext(UseTrimBidQuantity, TrimBidQuantity, TrimComparisonMode), 66 | new TrimContext(UseTrimDeltaAskBidQuantity, TrimDeltaAskBidQuantity, TrimComparisonMode), 67 | new TrimContext(UseTrimRelativeDeltaAskBidQuantityPercent, TrimRelativeDeltaAskBidQuantityPercent, TrimComparisonMode)); 68 | } 69 | 70 | protected override string GetParametersStateId() 71 | { 72 | return string.Join( 73 | ".", 74 | UseTrimTradesCount, 75 | TrimTradesCount, 76 | UseTrimQuantity, 77 | TrimQuantity, 78 | UseTrimAskQuantity, 79 | TrimAskQuantity, 80 | UseTrimBidQuantity, 81 | TrimBidQuantity, 82 | UseTrimDeltaAskBidQuantity, 83 | TrimDeltaAskBidQuantity, 84 | UseTrimRelativeDeltaAskBidQuantityPercent, 85 | TrimRelativeDeltaAskBidQuantityPercent, 86 | TrimComparisonMode); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsExtendedBarsHandler2.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TSLab.Script.Handlers 4 | { 5 | // Не стоит навешивать на абстрактные классы атрибуты категорий и описания входов/выходов 6 | public abstract class TradeStatisticsExtendedBarsHandler2 : TradeStatisticsBaseExtendedBarsHandler, ITradeStatisticsExtendedBarsHandler2 7 | { 8 | [HandlerParameter(true, NotOptimized = true)] 9 | public bool UseTrimTradesCount { get; set; } 10 | 11 | [HandlerParameter(true, "0", Min = "0", Max = "2147483647", Step = "1", EditorMin = "0")] 12 | public int TrimTradesCount { get; set; } 13 | 14 | [HandlerParameter(true, nameof(ComparisonMode.GreaterOrEqual))] 15 | public ComparisonMode TrimTradesCountComparisonMode { get; set; } 16 | 17 | [HandlerParameter(true, NotOptimized = true)] 18 | public bool UseTrimQuantity { get; set; } 19 | 20 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 21 | public double TrimQuantity { get; set; } 22 | 23 | [HandlerParameter(true, nameof(ComparisonMode.GreaterOrEqual))] 24 | public ComparisonMode TrimQuantityComparisonMode { get; set; } 25 | 26 | [HandlerParameter(true, NotOptimized = true)] 27 | public bool UseTrimAskQuantity { get; set; } 28 | 29 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 30 | public double TrimAskQuantity { get; set; } 31 | 32 | [HandlerParameter(true, nameof(ComparisonMode.GreaterOrEqual))] 33 | public ComparisonMode TrimAskQuantityComparisonMode { get; set; } 34 | 35 | [HandlerParameter(true, NotOptimized = true)] 36 | public bool UseTrimBidQuantity { get; set; } 37 | 38 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 39 | public double TrimBidQuantity { get; set; } 40 | 41 | [HandlerParameter(true, nameof(ComparisonMode.GreaterOrEqual))] 42 | public ComparisonMode TrimBidQuantityComparisonMode { get; set; } 43 | 44 | [HandlerParameter(true, NotOptimized = true)] 45 | public bool UseTrimDeltaAskBidQuantity { get; set; } 46 | 47 | [HandlerParameter(true, "0", Min = "-999999999999999", Max = "999999999999999", Step = "1")] 48 | public double TrimDeltaAskBidQuantity { get; set; } 49 | 50 | [HandlerParameter(true, nameof(ComparisonMode.GreaterOrEqual))] 51 | public ComparisonMode TrimDeltaAskBidQuantityComparisonMode { get; set; } 52 | 53 | [HandlerParameter(true, "false", NotOptimized = true)] 54 | public bool UseTrimRelativeDeltaAskBidQuantityPercent { get; set; } 55 | 56 | [HandlerParameter(true, "0", Min = "-100", Max = "100", Step = "1")] 57 | public double TrimRelativeDeltaAskBidQuantityPercent { get; set; } 58 | 59 | [HandlerParameter(true, nameof(ComparisonMode.GreaterOrEqual))] 60 | public ComparisonMode TrimRelativeDeltaAskBidQuantityPercentComparisonMode { get; set; } 61 | 62 | public IList Execute(IBaseTradeStatisticsWithKind tradeStatistics) 63 | { 64 | return Execute( 65 | tradeStatistics, 66 | new TrimContext(UseTrimTradesCount, TrimTradesCount, TrimTradesCountComparisonMode), 67 | new TrimContext(UseTrimQuantity, TrimQuantity, TrimQuantityComparisonMode), 68 | new TrimContext(UseTrimAskQuantity, TrimAskQuantity, TrimAskQuantityComparisonMode), 69 | new TrimContext(UseTrimBidQuantity, TrimBidQuantity, TrimBidQuantityComparisonMode), 70 | new TrimContext(UseTrimDeltaAskBidQuantity, TrimDeltaAskBidQuantity, TrimDeltaAskBidQuantityComparisonMode), 71 | new TrimContext(UseTrimRelativeDeltaAskBidQuantityPercent, TrimRelativeDeltaAskBidQuantityPercent, TrimRelativeDeltaAskBidQuantityPercentComparisonMode)); 72 | } 73 | 74 | protected override string GetParametersStateId() 75 | { 76 | return string.Join( 77 | ".", 78 | UseTrimTradesCount, 79 | TrimTradesCount, 80 | TrimTradesCountComparisonMode, 81 | UseTrimQuantity, 82 | TrimQuantity, 83 | TrimQuantityComparisonMode, 84 | UseTrimAskQuantity, 85 | TrimAskQuantity, 86 | TrimAskQuantityComparisonMode, 87 | UseTrimBidQuantity, 88 | TrimBidQuantity, 89 | TrimBidQuantityComparisonMode, 90 | UseTrimDeltaAskBidQuantity, 91 | TrimDeltaAskBidQuantity, 92 | TrimDeltaAskBidQuantityComparisonMode, 93 | UseTrimRelativeDeltaAskBidQuantityPercent, 94 | TrimRelativeDeltaAskBidQuantityPercent, 95 | TrimRelativeDeltaAskBidQuantityPercentComparisonMode); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsExtendedBarsSumHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | // TODO: английское описание 10 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 11 | [HelperName("Trade Statistics Extended Strings Sum 1", Language = Constants.En)] 12 | [HelperName("Расширенная сумма строк торговой статистики 1", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Блок 'Расширенная сумма строк торговой статистики 1' выдает значение, основанное на сумме значений строк торговой статистики.")] 18 | [HelperDescription("", Constants.En)] 19 | public sealed class TradeStatisticsExtendedBarsSumHandler : TradeStatisticsExtendedBarsHandler, ITradeStatisticsExtendedBarsSumHandler 20 | { 21 | /// 22 | /// \~english Kind of a trade statistics (trades count, trade volume, buy count, sell count, buy and sell difference, relative buy and sell difference). 23 | /// \~russian Вид торговой статистики (количество сделок, объем торгов, количество покупок, количество продаж, разница количества покупок и продаж, относительная разница количества покупок и продаж). 24 | /// 25 | [HelperName("Kind", Constants.En)] 26 | [HelperName("Вид", Constants.Ru)] 27 | [Description("Вид торговой статистики (количество сделок, объем торгов, количество покупок, количество продаж, разница количества покупок и продаж, относительная разница количества покупок и продаж).")] 28 | [HelperDescription("Kind of a trade statistics (trades count, trade volume, buy count, sell count, buy and sell difference, relative buy and sell difference).", Constants.En)] 29 | [HandlerParameter(true, nameof(TradeStatisticsKind.TradesCount))] 30 | public TradeStatisticsKind Kind { get; set; } 31 | 32 | protected override double GetResult(IBaseTradeStatisticsWithKind tradeStatistics, IEnumerable bars) 33 | { 34 | return bars.Sum(item => tradeStatistics.GetValue(item, Kind)); 35 | } 36 | 37 | protected override string GetParametersStateId() 38 | { 39 | return base.GetParametersStateId() + "." + Kind; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsExtendedBarsSumHandler2.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | // TODO: английское описание 10 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 11 | [HelperName("Trade Statistics Extended Strings Sum 2", Language = Constants.En)] 12 | [HelperName("Расширенная сумма строк торговой статистики 2", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Блок 'Расширенная сумма строк торговой статистики 2', выдает значение, основанное на сумме значений строк торговой статистики.")] 18 | [HelperDescription("", Constants.En)] 19 | public sealed class TradeStatisticsExtendedBarsSumHandler2 : TradeStatisticsExtendedBarsHandler2, ITradeStatisticsExtendedBarsSumHandler2 20 | { 21 | /// 22 | /// \~english Kind of a trade statistics (trades count, trade volume, buy count, sell count, buy and sell difference, relative buy and sell difference). 23 | /// \~russian Вид торговой статистики (количество сделок, объем торгов, количество покупок, количество продаж, разница количества покупок и продаж, относительная разница количества покупок и продаж). 24 | /// 25 | [HelperName("Kind", Constants.En)] 26 | [HelperName("Вид", Constants.Ru)] 27 | [Description("Вид торговой статистики (количество сделок, объем торгов, количество покупок, количество продаж, разница количества покупок и продаж, относительная разница количества покупок и продаж).")] 28 | [HelperDescription("Kind of a trade statistics (trades count, trade volume, buy count, sell count, buy and sell difference, relative buy and sell difference).", Constants.En)] 29 | [HandlerParameter(true, nameof(TradeStatisticsKind.TradesCount))] 30 | public TradeStatisticsKind Kind { get; set; } 31 | 32 | protected override double GetResult(IBaseTradeStatisticsWithKind tradeStatistics, IEnumerable bars) 33 | { 34 | return bars.Sum(item => tradeStatistics.GetValue(item, Kind)); 35 | } 36 | 37 | protected override string GetParametersStateId() 38 | { 39 | return base.GetParametersStateId() + "." + Kind; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsExtendedExtremumPriceHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using TSLab.Script.Handlers.Options; 4 | 5 | namespace TSLab.Script.Handlers 6 | { 7 | // TODO: английское описание 8 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 9 | [HelperName("Trade Statistics Extended Extremum Price 1", Language = Constants.En)] 10 | [HelperName("Расширенная экстремальная цена торговой статистики 1", Language = Constants.Ru)] 11 | [InputsCount(1)] 12 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 13 | [OutputsCount(1)] 14 | [OutputType(TemplateTypes.DOUBLE)] 15 | [Description("Блок 'Расширенная экстремальная цена торговой статистики 1' показывает максимальное значение торговой статистики при экстремальной цене.")] 16 | [HelperDescription("", Constants.En)] 17 | public sealed class TradeStatisticsExtendedExtremumPriceHandler : TradeStatisticsBaseExtendedExtremumPriceHandler, ITradeStatisticsExtendedExtremumPriceHandler 18 | { 19 | [HandlerParameter(true, NotOptimized = true)] 20 | public bool UseTrimTradesCount { get; set; } 21 | 22 | [HandlerParameter(true, "0", Min = "0", Max = "2147483647", Step = "1", EditorMin = "0")] 23 | public int TrimTradesCount { get; set; } 24 | 25 | [HandlerParameter(true, NotOptimized = true)] 26 | public bool UseTrimQuantity { get; set; } 27 | 28 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 29 | public double TrimQuantity { get; set; } 30 | 31 | [HandlerParameter(true, NotOptimized = true)] 32 | public bool UseTrimAskQuantity { get; set; } 33 | 34 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 35 | public double TrimAskQuantity { get; set; } 36 | 37 | [HandlerParameter(true, NotOptimized = true)] 38 | public bool UseTrimBidQuantity { get; set; } 39 | 40 | [HandlerParameter(true, "0", Min = "0", Max = "999999999999999", Step = "1", EditorMin = "0")] 41 | public double TrimBidQuantity { get; set; } 42 | 43 | [HandlerParameter(true, NotOptimized = true)] 44 | public bool UseTrimDeltaAskBidQuantity { get; set; } 45 | 46 | [HandlerParameter(true, "0", Min = "-999999999999999", Max = "999999999999999", Step = "1")] 47 | public double TrimDeltaAskBidQuantity { get; set; } 48 | 49 | [HandlerParameter(true, "false", NotOptimized = true)] 50 | public bool UseTrimRelativeDeltaAskBidQuantityPercent { get; set; } 51 | 52 | [HandlerParameter(true, "0", Min = "-100", Max = "100", Step = "1")] 53 | public double TrimRelativeDeltaAskBidQuantityPercent { get; set; } 54 | 55 | [HandlerParameter(true, nameof(ComparisonMode.GreaterOrEqual))] 56 | public ComparisonMode TrimComparisonMode { get; set; } 57 | 58 | public override IList Execute(IBaseTradeStatisticsWithKind tradeStatistics) 59 | { 60 | return Execute( 61 | tradeStatistics, 62 | new TrimContext(UseTrimTradesCount, TrimTradesCount, TrimComparisonMode), 63 | new TrimContext(UseTrimQuantity, TrimQuantity, TrimComparisonMode), 64 | new TrimContext(UseTrimAskQuantity, TrimAskQuantity, TrimComparisonMode), 65 | new TrimContext(UseTrimBidQuantity, TrimBidQuantity, TrimComparisonMode), 66 | new TrimContext(UseTrimDeltaAskBidQuantity, TrimDeltaAskBidQuantity, TrimComparisonMode), 67 | new TrimContext(UseTrimRelativeDeltaAskBidQuantityPercent, TrimRelativeDeltaAskBidQuantityPercent, TrimComparisonMode)); 68 | } 69 | 70 | protected override string GetParametersStateId() 71 | { 72 | return string.Join( 73 | ".", 74 | base.GetParametersStateId(), 75 | UseTrimTradesCount, 76 | TrimTradesCount, 77 | UseTrimQuantity, 78 | TrimQuantity, 79 | UseTrimAskQuantity, 80 | TrimAskQuantity, 81 | UseTrimBidQuantity, 82 | TrimBidQuantity, 83 | UseTrimDeltaAskBidQuantity, 84 | TrimDeltaAskBidQuantity, 85 | UseTrimRelativeDeltaAskBidQuantityPercent, 86 | TrimRelativeDeltaAskBidQuantityPercent, 87 | TrimComparisonMode); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsLowerEdgeHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | // TODO: английское описание 10 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 11 | [HelperName("Trade Statistics Lower Edge", Language = Constants.En)] 12 | [HelperName("Нижний уровень торговой статистики", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Кубик 'Нижний уровень торговой статистики' позволяет установить в процентном значении отсечку данных по нижнему уровню. Данный блок соединяется с блоком 'Торговая статистика'.")] 18 | [HelperDescription("", Constants.En)] 19 | public sealed class TradeStatisticsLowerEdgeHandler : TradeStatisticsEdgeHandler 20 | { 21 | protected override double GetFirstPrice(IReadOnlyList bars) 22 | { 23 | return bars.First().MinPrice; 24 | } 25 | 26 | protected override double GetLastPrice(IReadOnlyList bars) 27 | { 28 | return bars.Last().MaxPrice; 29 | } 30 | 31 | protected override IEnumerable GetOrderedBars(IEnumerable bars) 32 | { 33 | return bars; 34 | } 35 | 36 | protected override double GetPrice(ITradeHistogramBar bar, double coefficient) 37 | { 38 | double result; 39 | if (coefficient < 0.5) 40 | result = bar.MinPrice + (bar.AveragePrice - bar.MinPrice) * coefficient * 2; 41 | else if (coefficient > 0.5) 42 | result = bar.AveragePrice + (bar.MaxPrice - bar.AveragePrice) * (coefficient - 0.5) * 2; 43 | else 44 | result = bar.AveragePrice; 45 | 46 | return result; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ClusterAnalysis/TradeStatisticsUpperEdgeHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | // TODO: английское описание 10 | [HandlerCategory(HandlerCategories.ClusterAnalysis)] 11 | [HelperName("Trade Statistics Upper Edge", Language = Constants.En)] 12 | [HelperName("Верхний уровень торговой статистики", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.TRADE_STATISTICS | TemplateTypes.LAST_CONTRACTS_TRADE_STATISTICS)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Блок 'Верхний уровень торговой статистики' позволяет установить в процентном значении отсечки данных по верхнему уровню. Данный блок соединяется с блоком 'Торговая статистика'.")] 18 | [HelperDescription("", Constants.En)] 19 | public sealed class TradeStatisticsUpperEdgeHandler : TradeStatisticsEdgeHandler 20 | { 21 | protected override double GetFirstPrice(IReadOnlyList bars) 22 | { 23 | return bars.Last().MaxPrice; 24 | } 25 | 26 | protected override double GetLastPrice(IReadOnlyList bars) 27 | { 28 | return bars.First().MinPrice; 29 | } 30 | 31 | protected override IEnumerable GetOrderedBars(IEnumerable bars) 32 | { 33 | return bars.Reverse(); 34 | } 35 | 36 | protected override double GetPrice(ITradeHistogramBar bar, double coefficient) 37 | { 38 | double result; 39 | if (coefficient < 0.5) 40 | result = bar.MaxPrice + (bar.AveragePrice - bar.MaxPrice) * coefficient * 2; 41 | else if (coefficient > 0.5) 42 | result = bar.AveragePrice + (bar.MinPrice - bar.AveragePrice) * (coefficient - 0.5) * 2; 43 | else 44 | result = bar.AveragePrice; 45 | 46 | return result; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ConstList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace TSLab.Script.Handlers 6 | { 7 | internal sealed class ConstList : IList, IReadOnlyList 8 | { 9 | private static readonly IEqualityComparer s_equalityComparer = EqualityComparer.Default; 10 | private readonly T m_value; 11 | 12 | public ConstList(int count, T value) 13 | { 14 | if (count < 0) 15 | throw new ArgumentOutOfRangeException(nameof(count)); 16 | 17 | Count = count; 18 | m_value = value; 19 | } 20 | 21 | public IEnumerator GetEnumerator() 22 | { 23 | for (var i = 0; i < Count; i++) 24 | yield return m_value; 25 | } 26 | 27 | IEnumerator IEnumerable.GetEnumerator() 28 | { 29 | return GetEnumerator(); 30 | } 31 | 32 | public void Add(T item) 33 | { 34 | throw new NotSupportedException(); 35 | } 36 | 37 | public void Clear() 38 | { 39 | throw new NotSupportedException(); 40 | } 41 | 42 | public bool Contains(T item) 43 | { 44 | return Count > 0 && s_equalityComparer.Equals(m_value, item); 45 | } 46 | 47 | public void CopyTo(T[] array, int arrayIndex) 48 | { 49 | throw new NotSupportedException(); 50 | } 51 | 52 | public bool Remove(T item) 53 | { 54 | throw new NotSupportedException(); 55 | } 56 | 57 | public int Count { get; } 58 | 59 | public bool IsReadOnly => true; 60 | 61 | public int IndexOf(T item) 62 | { 63 | return Contains(item) ? 0 : -1; 64 | } 65 | 66 | public void Insert(int index, T item) 67 | { 68 | throw new NotSupportedException(); 69 | } 70 | 71 | public void RemoveAt(int index) 72 | { 73 | throw new NotSupportedException(); 74 | } 75 | 76 | public T this[int index] 77 | { 78 | get 79 | { 80 | if (index < 0 || index >= Count) 81 | throw new ArgumentOutOfRangeException(nameof(index)); 82 | 83 | return m_value; 84 | } 85 | set { throw new NotSupportedException(); } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Cycle/AddPositionHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using TSLab.Script.Handlers; 5 | 6 | namespace TSLab.ScriptEngine.Template 7 | { 8 | [HandlerInvisible] 9 | [OutputsCount(0)] 10 | public sealed class AddPositionHandler : IHandler 11 | { 12 | [HandlerParameter(true, "false", NotOptimized = true)] 13 | public bool UseVirtualClosing { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Cycle/CycleBoolHandler.cs: -------------------------------------------------------------------------------- 1 | namespace TSLab.Script.Handlers 2 | { 3 | [HandlerInvisible] 4 | [OutputType(TemplateTypes.BOOL)] 5 | public abstract class CycleBoolHandler : IValuesHandlerWithNumber, IOneSourceHandler, IBooleanInputs, IBooleanReturns 6 | { 7 | private int m_barIndex = -1; 8 | private bool m_result; 9 | private bool m_value; 10 | 11 | public bool Execute(bool value, int barIndex) 12 | { 13 | if (m_barIndex != barIndex) 14 | { 15 | m_barIndex = barIndex; 16 | m_result = m_value; 17 | m_value = value; 18 | } 19 | else 20 | m_value = Execute(m_value, value); 21 | 22 | return m_result; 23 | } 24 | 25 | protected abstract bool Execute(bool value1, bool value2); 26 | } 27 | 28 | public sealed class CycleAndHandler : CycleBoolHandler 29 | { 30 | protected override bool Execute(bool value1, bool value2) => value1 && value2; 31 | } 32 | 33 | public sealed class CycleOrHandler : CycleBoolHandler 34 | { 35 | protected override bool Execute(bool value1, bool value2) => value1 || value2; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Cycle/CycleHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TSLab.Script.Handlers 4 | { 5 | [HandlerInvisible] 6 | [OutputType(TemplateTypes.INT)] 7 | public sealed class CycleHandler : IHandler 8 | { 9 | [HandlerParameter(true, "1", Min = "1", Max = "2147483647", Step = "1", EditorMin = "1", EditorMax = "2147483647")] 10 | public int MaxCount { get; set; } 11 | 12 | public int GetCount(double value) 13 | { 14 | if (double.IsNaN(value)) 15 | return 0; 16 | 17 | if (value <= int.MinValue) 18 | return int.MinValue; 19 | 20 | if (value >= int.MaxValue) 21 | return int.MaxValue; 22 | 23 | return GetCount((int)Math.Round(value, MidpointRounding.AwayFromZero)); 24 | } 25 | 26 | public int GetCount(int value) 27 | { 28 | return Math.Min(MaxCount, value); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Cycle/CycleResultHandler.cs: -------------------------------------------------------------------------------- 1 | namespace TSLab.Script.Handlers 2 | { 3 | [HandlerInvisible] 4 | public abstract class CycleResultHandler : IHandler 5 | { 6 | [HandlerParameter(true, "0", Min = "0", Max = "2147483647", Step = "1", EditorMin = "0", EditorMax = "2147483647")] 7 | public int Index { get; set; } 8 | 9 | [HandlerParameter(true, "true")] 10 | public bool UseLastIndex { get; set; } 11 | } 12 | 13 | [OutputType(TemplateTypes.BOOL)] 14 | public sealed class CycleBoolResultHandler : CycleResultHandler 15 | { 16 | } 17 | 18 | [OutputType(TemplateTypes.DOUBLE)] 19 | public sealed class CycleDoubleResultHandler : CycleResultHandler 20 | { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Cycle/CycleResultsHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace TSLab.Script.Handlers 6 | { 7 | [HandlerInvisible] 8 | public abstract class CycleResultsHandler : IValuesHandlerWithNumber, IOneSourceHandler, IContextUses 9 | { 10 | private sealed class ExReadOnlyList : IList, IReadOnlyList 11 | { 12 | private readonly IReadOnlyList m_src; 13 | 14 | public ExReadOnlyList(IReadOnlyList src) 15 | { 16 | m_src = src; 17 | } 18 | 19 | public IEnumerator GetEnumerator() 20 | { 21 | return m_src.GetEnumerator(); 22 | } 23 | 24 | IEnumerator IEnumerable.GetEnumerator() 25 | { 26 | return GetEnumerator(); 27 | } 28 | 29 | public void Add(T item) 30 | { 31 | throw new NotSupportedException(); 32 | } 33 | 34 | public void Clear() 35 | { 36 | throw new NotSupportedException(); 37 | } 38 | 39 | public bool Contains(T item) 40 | { 41 | throw new NotSupportedException(); 42 | } 43 | 44 | public void CopyTo(T[] array, int arrayIndex) 45 | { 46 | throw new NotSupportedException(); 47 | } 48 | 49 | public bool Remove(T item) 50 | { 51 | throw new NotSupportedException(); 52 | } 53 | 54 | public int Count => m_src.Count; 55 | 56 | public bool IsReadOnly => true; 57 | 58 | public int IndexOf(T item) 59 | { 60 | throw new NotSupportedException(); 61 | } 62 | 63 | public void Insert(int index, T item) 64 | { 65 | throw new NotSupportedException(); 66 | } 67 | 68 | public void RemoveAt(int index) 69 | { 70 | throw new NotSupportedException(); 71 | } 72 | 73 | public T this[int index] 74 | { 75 | get => index < Count ? m_src[index] : default(T); 76 | set => throw new NotSupportedException(); 77 | } 78 | } 79 | 80 | private readonly List> m_listOfLists = new List>(); 81 | private readonly List m_list = new List(); 82 | private IContext m_context; 83 | 84 | public IContext Context 85 | { 86 | get => m_context; 87 | set 88 | { 89 | m_context = value; 90 | m_list.Capacity = value.BarsCount; 91 | } 92 | } 93 | 94 | public IReadOnlyList> Execute(T value, int barIndex) 95 | { 96 | if (m_listOfLists.Count == barIndex) 97 | { 98 | if (barIndex > 0) 99 | m_listOfLists[barIndex - 1] = new ExReadOnlyList(m_list.ToArray()); 100 | 101 | m_list.Clear(); 102 | m_listOfLists.Add(m_list); 103 | } 104 | m_list.Add(value); 105 | return m_listOfLists; 106 | } 107 | } 108 | 109 | [OutputType(TemplateTypes.BOOL | TemplateTypes.LIST_OF_LISTS)] 110 | public sealed class CycleBoolResultsHandler : CycleResultsHandler, IBooleanInputs 111 | { 112 | } 113 | 114 | [OutputType(TemplateTypes.DOUBLE | TemplateTypes.LIST_OF_LISTS)] 115 | public sealed class CycleDoubleResultsHandler : CycleResultsHandler, IDoubleInputs 116 | { 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Cycle/CycleValueUpdaterHandler.cs: -------------------------------------------------------------------------------- 1 | namespace TSLab.Script.Handlers 2 | { 3 | [HandlerInvisible] 4 | [OutputType(TemplateTypes.DOUBLE)] 5 | public sealed class CycleValueUpdaterHandler : IHandler 6 | { 7 | [HandlerParameter(false, "0", NotOptimized = true)] 8 | public double StartFrom { get; set; } 9 | 10 | [HandlerParameter(false, nameof(ValueUpdaterExecutionOrder.AtTheEnd), NotOptimized = true)] 11 | public ValueUpdaterExecutionOrder ExecutionOrder { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GraphPane/InteractiveLineGen.BaseList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace TSLab.Script.Handlers 6 | { 7 | public sealed partial class InteractiveLineGen 8 | { 9 | private abstract class BaseList : IList 10 | { 11 | protected BaseList(int count) 12 | : this(count, 0, count - 1) 13 | { 14 | } 15 | 16 | protected BaseList(int count, int minIndex, int maxIndex) 17 | { 18 | if (count == 0) 19 | { 20 | if (minIndex != -1) 21 | throw new ArgumentOutOfRangeException(nameof(minIndex)); 22 | 23 | if (maxIndex != -1) 24 | throw new ArgumentOutOfRangeException(nameof(maxIndex)); 25 | } 26 | else if (count > 0) 27 | { 28 | if (minIndex < 0) 29 | throw new ArgumentOutOfRangeException(nameof(minIndex)); 30 | 31 | if (maxIndex >= count) 32 | throw new ArgumentOutOfRangeException(nameof(maxIndex)); 33 | 34 | if (minIndex > maxIndex) 35 | throw new ArgumentOutOfRangeException(nameof(maxIndex)); 36 | } 37 | else 38 | throw new ArgumentOutOfRangeException(nameof(count)); 39 | 40 | Count = count; 41 | MinIndex = minIndex; 42 | MaxIndex = maxIndex; 43 | } 44 | 45 | public IEnumerator GetEnumerator() 46 | { 47 | if (Count > 0) 48 | { 49 | for (var i = 0; i < MinIndex; i++) 50 | yield return double.NaN; 51 | 52 | for (var i = MinIndex; i <= MaxIndex; i++) 53 | yield return GetValue(i); 54 | 55 | for (var i = MaxIndex + 1; i < Count; i++) 56 | yield return double.NaN; 57 | } 58 | else 59 | yield return double.NaN; 60 | } 61 | 62 | IEnumerator IEnumerable.GetEnumerator() 63 | { 64 | return GetEnumerator(); 65 | } 66 | 67 | public void Add(double item) 68 | { 69 | throw new NotSupportedException(); 70 | } 71 | 72 | public void Clear() 73 | { 74 | throw new NotSupportedException(); 75 | } 76 | 77 | public bool Contains(double item) 78 | { 79 | return IndexOf(item) >= 0; 80 | } 81 | 82 | public void CopyTo(double[] array, int arrayIndex) 83 | { 84 | throw new NotSupportedException(); 85 | } 86 | 87 | public bool Remove(double item) 88 | { 89 | throw new NotSupportedException(); 90 | } 91 | 92 | public int Count { get; } 93 | 94 | public bool IsReadOnly 95 | { 96 | get { return true; } 97 | } 98 | 99 | public abstract int IndexOf(double item); 100 | 101 | public void Insert(int index, double item) 102 | { 103 | throw new NotSupportedException(); 104 | } 105 | 106 | public void RemoveAt(int index) 107 | { 108 | throw new NotSupportedException(); 109 | } 110 | 111 | public double this[int index] 112 | { 113 | get { return index >= MinIndex && index <= MaxIndex ? GetValue(index) : double.NaN; } 114 | set { throw new NotSupportedException(); } 115 | } 116 | 117 | protected int MinIndex { get; } 118 | 119 | protected int MaxIndex { get; } 120 | 121 | protected abstract double GetValue(int index); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /GraphPane/InteractiveLineGen.ConstList.cs: -------------------------------------------------------------------------------- 1 | namespace TSLab.Script.Handlers 2 | { 3 | public sealed partial class InteractiveLineGen 4 | { 5 | private sealed class ConstList : BaseList 6 | { 7 | private readonly double m_value; 8 | 9 | public ConstList(double value, int count) 10 | : base(count) 11 | { 12 | m_value = value; 13 | } 14 | 15 | public ConstList(double value, int count, int minIndex, int maxIndex) 16 | : base(count, minIndex, maxIndex) 17 | { 18 | m_value = value; 19 | } 20 | 21 | public override int IndexOf(double item) 22 | { 23 | return m_value == item ? MinIndex : -1; 24 | } 25 | 26 | protected override double GetValue(int index) 27 | { 28 | return m_value; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GraphPane/InteractiveLineGen.LineList.cs: -------------------------------------------------------------------------------- 1 | namespace TSLab.Script.Handlers 2 | { 3 | public sealed partial class InteractiveLineGen 4 | { 5 | private sealed class LineList : BaseList 6 | { 7 | private readonly double m_a; 8 | private readonly double m_b; 9 | 10 | public LineList(double a, double b, int count, int minIndex, int maxIndex) 11 | : base(count, minIndex, maxIndex) 12 | { 13 | m_a = a; 14 | m_b = b; 15 | } 16 | 17 | public override int IndexOf(double item) 18 | { 19 | var minValue = GetValue(MinIndex); 20 | var maxValue = GetValue(MaxIndex); 21 | 22 | if (minValue > maxValue) 23 | { 24 | var value = minValue; 25 | minValue = maxValue; 26 | maxValue = value; 27 | } 28 | if (item >= minValue && item <= maxValue) 29 | for (var i = MinIndex; i <= MaxIndex; i++) 30 | if (GetValue(i) == item) 31 | return i; 32 | 33 | return -1; 34 | } 35 | 36 | protected override double GetValue(int index) 37 | { 38 | return m_a * index + m_b; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /HelperDescriptionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace TSLab.Script.Handlers.Options 5 | { 6 | /// 7 | /// Описание кубика как его будет видеть Пользователь. 8 | /// Это вспомогательный атрибут для упрощения локализации зоопарка кубиков (как опционных, так и обычных). 9 | /// 10 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)] 11 | public class HelperDescriptionAttribute : Attribute 12 | { 13 | public HelperDescriptionAttribute() 14 | : this(String.Empty, Constants.Ru) 15 | { 16 | } 17 | 18 | public HelperDescriptionAttribute(string description) 19 | : this(description, Constants.Ru) 20 | { 21 | } 22 | 23 | public HelperDescriptionAttribute(string description, string language) 24 | { 25 | Description = description ?? String.Empty; 26 | Language = String.IsNullOrWhiteSpace(language) ? Constants.Ru : language; 27 | } 28 | 29 | public string Description { get; set; } 30 | 31 | public string Language { get; set; } 32 | 33 | public override string ToString() 34 | { 35 | return Description; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /HelperLinkAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace TSLab.Script.Handlers.Options 5 | { 6 | /// 7 | /// Ссылка на скрипт или статью с использованием данного кубика. 8 | /// Это вспомогательный атрибут для упрощения локализации зоопарка кубиков (как опционных, так и обычных), 9 | /// а также для автоматизированного формирования документации. 10 | /// 11 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)] 12 | public class HelperLinkAttribute : Attribute 13 | { 14 | public HelperLinkAttribute(string link) 15 | : this(link, link, Constants.Ru) 16 | { 17 | } 18 | 19 | public HelperLinkAttribute(string link, string name, string language) 20 | { 21 | Link = link ?? String.Empty; 22 | Name = name ?? String.Empty; 23 | Language = String.IsNullOrWhiteSpace(language) ? Constants.Ru : language; 24 | } 25 | 26 | public string Link { get; set; } 27 | 28 | public string Name { get; set; } 29 | 30 | public string Language { get; set; } 31 | 32 | public override string ToString() 33 | { 34 | return Name + ": " + Link; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /HelperNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace TSLab.Script.Handlers.Options 5 | { 6 | /// 7 | /// Название кубика как его будет видеть Пользователь. 8 | /// Вспомогательный атрибут для упрощения локализации зоопарка кубиков (как опционных, так и обычных), 9 | /// а также для автоматизированного формирования документации. 10 | /// 11 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)] 12 | public class HelperNameAttribute : Attribute 13 | { 14 | public HelperNameAttribute(string name) 15 | : this(name, Constants.Ru) 16 | { 17 | } 18 | 19 | public HelperNameAttribute(string name, string language) 20 | { 21 | Name = name ?? String.Empty; 22 | Language = String.IsNullOrWhiteSpace(language) ? Constants.Ru : language; 23 | } 24 | 25 | public string Name { get; set; } 26 | 27 | public string Language { get; set; } 28 | 29 | public override string ToString() 30 | { 31 | return Name; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Indicators/AMA.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | // ReSharper disable InconsistentNaming 8 | namespace TSLab.Script.Handlers 9 | { 10 | [HandlerCategory(HandlerCategories.Indicators)] 11 | [HelperName("AMA", Language = Constants.En)] 12 | [HelperName("AMA", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.DOUBLE)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Адаптивное сглаженное скользящее среднее.")] 18 | [HelperDescription("The Adaptive Moving Average.", Constants.En)] 19 | public sealed class AMA : DoubleStreamAndValuesHandlerWithPeriod 20 | { 21 | private ShrinkedList m_source; 22 | private double m_lastResult; 23 | 24 | public override bool IsGapTolerant 25 | { 26 | get { return false; } 27 | } 28 | 29 | public override IList Execute(IList source) 30 | { 31 | return Calc(source, Period, Context); 32 | } 33 | 34 | protected override void InitExecuteContext() 35 | { 36 | m_source = new ShrinkedList(Period + 2); 37 | m_lastResult = 0; 38 | } 39 | 40 | protected override void ClearExecuteContext() 41 | { 42 | m_source = null; 43 | m_lastResult = 0; 44 | } 45 | 46 | protected override void InitForGap() 47 | { 48 | var firstIndex = Math.Max(m_executeContext.LastIndex + 1, m_executeContext.Index - 7 * Period); 49 | for (var i = firstIndex; i < m_executeContext.Index; i++) 50 | { 51 | m_source.Add(m_executeContext.GetSourceForGap(i)); 52 | m_lastResult = Calc(m_source, m_lastResult, m_source.Count - 1, Period); 53 | } 54 | } 55 | 56 | protected override double Execute() 57 | { 58 | m_source.Add(m_executeContext.Source); 59 | m_lastResult = Calc(m_source, m_lastResult, m_source.Count - 1, Period); 60 | return m_lastResult; 61 | } 62 | 63 | public static IList Calc(IList source, int period, IMemoryContext context = null) 64 | { 65 | if (source == null) 66 | throw new ArgumentNullException(nameof(source)); 67 | 68 | if (period <= 0) 69 | throw new ArgumentOutOfRangeException(nameof(period)); 70 | 71 | var result = context?.GetArray(source.Count) ?? new double[source.Count]; 72 | if (result.Length > 0) 73 | { 74 | result[0] = Calc(source, 0, 0, period); 75 | for (var i = 1; i < result.Length; i++) 76 | result[i] = Calc(source, result[i - 1], i, period); 77 | } 78 | return result; 79 | } 80 | 81 | private static double Calc(IList source, double lastResult, int index, int period) 82 | { 83 | if (index <= period) 84 | return source[index]; 85 | 86 | var signal = Math.Abs(source[index] - source[index - period]); 87 | var noise = 0.000000001; 88 | 89 | for (var i = 0; i < period; i++) 90 | noise = noise + Math.Abs(source[index - i] - source[index - i - 1]); 91 | 92 | var er = signal / noise; 93 | var ssc = (er * 0.60215) + 0.06452; 94 | var cst = Math.Pow(ssc, 2); 95 | var result = lastResult + cst * (source[index] - lastResult); 96 | return result; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Indicators/BarsCountForValuesSumHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using TSLab.Script.Handlers.Options; 5 | using TSLab.Utils; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | [HandlerCategory(HandlerCategories.Indicators)] 10 | [HelperName("Bars count for values sum", Language = Constants.En)] 11 | [HelperName("Количество баров для суммы значений", Language = Constants.Ru)] 12 | [Description("Количество баров для суммы значений")] 13 | [HelperDescription("Bars count for values sum", Constants.En)] 14 | public sealed class BarsCountForValuesSumHandler : DoubleStreamAndValuesHandler 15 | { 16 | private double[] m_source; 17 | 18 | public override bool IsGapTolerant => false; 19 | 20 | /// 21 | /// \~english Indicator values sum 22 | /// \~russian Сумма значений индикатора 23 | /// 24 | [HelperName("Values sum", Constants.En)] 25 | [HelperName("Сумма значений", Constants.Ru)] 26 | [Description("Сумма значений индикатора")] 27 | [HelperDescription("Indicator values sum", Constants.En)] 28 | [HandlerParameter(true, "1", Min = "0", Max = "2147483647", Step = "1", EditorMin = "1")] 29 | public double ValuesSum { get; set; } 30 | 31 | public override IList Execute(IList source) 32 | { 33 | if (source == null) 34 | throw new ArgumentNullException(nameof(source)); 35 | 36 | if (source.Count == 0) 37 | return EmptyArrays.Double; 38 | 39 | var results = Context.GetArray(source.Count); 40 | for (var i = 0; i < source.Count; i++) 41 | results[i] = Calculate(source, i); 42 | 43 | return results; 44 | } 45 | 46 | protected override void InitExecuteContext() 47 | { 48 | m_source = Context.GetArray(Context.BarsCount); 49 | } 50 | 51 | protected override void ClearExecuteContext() 52 | { 53 | Context.ReleaseArray(m_source); 54 | m_source = null; 55 | } 56 | 57 | protected override void InitForGap() 58 | { 59 | for (var i = m_executeContext.LastIndex; i < m_executeContext.Index; i++) 60 | m_source[i] = m_executeContext.GetSourceForGap(i); 61 | } 62 | 63 | protected override double Execute() 64 | { 65 | var index = m_executeContext.Index; 66 | m_source[index] = m_executeContext.Source; 67 | return Calculate(m_source, index); 68 | } 69 | 70 | private double Calculate(IList source, int index) 71 | { 72 | var valuesSum = 0D; 73 | for (var j = index; j >= 0; j--) 74 | { 75 | valuesSum += source[j]; 76 | if (valuesSum >= ValuesSum) 77 | return index - j + 1; 78 | } 79 | return 0; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Indicators/DoubleStreamAndValuesHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | public abstract class DoubleStreamAndValuesHandler : IDoubleStreamAndValuesHandler 10 | { 11 | protected sealed class ExecuteContext 12 | { 13 | private double m_a; 14 | private double m_b; 15 | 16 | public double Source { get; set; } 17 | public int Index { get; set; } 18 | public double LastResult { get; set; } 19 | public double LastSource { get; set; } 20 | public int LastIndex { get; set; } 21 | 22 | public void InitForGap() 23 | { 24 | if (LastIndex < 0) 25 | { 26 | m_a = 0; 27 | m_b = Source; 28 | } 29 | else 30 | { 31 | m_a = (LastSource - Source) / (LastIndex - Index); 32 | m_b = LastSource - m_a * LastIndex; 33 | } 34 | } 35 | 36 | public double GetSourceForGap(int i) 37 | { 38 | var source = m_a * i + m_b; 39 | return source; 40 | } 41 | } 42 | 43 | protected ExecuteContext m_executeContext; 44 | 45 | public IContext Context { get; set; } 46 | 47 | public abstract bool IsGapTolerant { get; } 48 | 49 | public abstract IList Execute(IList source); 50 | 51 | public double Execute(double source, int index) 52 | { 53 | if (index < 0 || index >= Context.BarsCount) 54 | throw new ArgumentOutOfRangeException(nameof(index)); 55 | 56 | if (m_executeContext != null) 57 | { 58 | if (index < m_executeContext.LastIndex) 59 | throw new ArgumentException(nameof(index)); 60 | 61 | if (index == m_executeContext.LastIndex) 62 | return m_executeContext.LastResult; 63 | 64 | m_executeContext.Source = source; 65 | m_executeContext.Index = index; 66 | } 67 | else 68 | { 69 | m_executeContext = new ExecuteContext { Source = source, Index = index, LastIndex = -1 }; 70 | InitExecuteContext(); 71 | } 72 | if (index - m_executeContext.LastIndex > 1) 73 | { 74 | m_executeContext.InitForGap(); 75 | InitForGap(); 76 | } 77 | m_executeContext.LastResult = Execute(); 78 | m_executeContext.LastSource = source; 79 | m_executeContext.LastIndex = index; 80 | 81 | if (index == Context.BarsCount - 1) 82 | ClearExecuteContext(); 83 | 84 | return m_executeContext.LastResult; 85 | } 86 | 87 | protected abstract void InitExecuteContext(); 88 | 89 | protected abstract void ClearExecuteContext(); 90 | 91 | protected abstract void InitForGap(); 92 | 93 | protected abstract double Execute(); 94 | } 95 | 96 | public abstract class DoubleStreamAndValuesHandlerWithPeriod : DoubleStreamAndValuesHandler, IDoubleStreamAndValuesHandlerWithPeriod 97 | { 98 | protected const int GapTolerancePeriodMultiplier = 2; 99 | private int m_period = 1; 100 | 101 | /// 102 | /// \~english Indicator period (processing window) 103 | /// \~russian Период индикатора (окно расчетов) 104 | /// 105 | [HelperName("Period", Constants.En)] 106 | [HelperName("Период", Constants.Ru)] 107 | [Description("Период индикатора (окно расчетов)")] 108 | [HelperDescription("Indicator period (processing window)", Constants.En)] 109 | [HandlerParameter(true, "20", Min = "10", Max = "100", Step = "5", EditorMin = "1")] 110 | public int Period 111 | { 112 | get { return m_period; } 113 | set { m_period = Math.Max(value, 1); } 114 | } 115 | 116 | protected virtual bool IsSimple 117 | { 118 | get { return Period == 1 || Context.BarsCount == 1; } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Indicators/SomeIndicators.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Globalization; 6 | 7 | using TSLab.Script.Handlers.Options; 8 | using TSLab.Script.Helpers; 9 | 10 | // ReSharper disable UnusedMember.Global 11 | // ReSharper disable MemberCanBePrivate.Global 12 | // ReSharper disable UnusedAutoPropertyAccessor.Global 13 | // ReSharper disable ClassNeverInstantiated.Global 14 | // ReSharper disable InconsistentNaming 15 | // ReSharper disable CompareOfFloatsByEqualityOperator 16 | namespace TSLab.Script.Handlers 17 | { 18 | [HandlerCategory(HandlerCategories.Indicators)] 19 | [HelperName("StochK", Language = Constants.En)] 20 | [HelperName("StochK", Language = Constants.Ru)] 21 | #region Атрибуты с описанием и ссылками 22 | [InputsCount(1)] 23 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 24 | [OutputsCount(1)] 25 | [OutputType(TemplateTypes.DOUBLE)] 26 | [Description("Стохастический осциллятор (Stochastic Oscillator) = (Цена закрытия текущего бара - Минимальное значение за период от минимума бара) / (Максимальное значение за период от максимума бара - Минимальное значение за период от минимума бара) * 100. " + 27 | "Стохастический осциллятор измеряет насколько цена близка к своим верхним или нижним границам. Индикатор изменяется в диапазоне от 0 до 100.")] 28 | [HelperDescription("The Stochastic Oscillator = (Current bar closing price - Period minimum value calculated on bar minimum) / (Bar maximum value calculated on bar maximum - Bar minimum value based on bar minimum) * 100. " + 29 | "This indicator shows how close price is to its upper and lower borders.The indicator varies in the range from 0 to 100.", Constants.En)] 30 | [HelperLink(@"http://www.tslab.ru/files/script/StochK.xml", "Пример по индикатору Stochastic K", Constants.Ru)] 31 | [HelperLink(@"http://www.tslab.ru/files/script/StochK.xml", "Example of Stochastic K", Constants.En)] 32 | #endregion Атрибуты с описанием и ссылками 33 | public sealed class StochK : BasePeriodIndicatorHandler, IBar2DoubleHandler, IContextUses 34 | { 35 | public IList Execute(ISecurity source) 36 | { 37 | var high = Context.GetData("Highest", new[] { Period.ToString(CultureInfo.InvariantCulture), source.CacheName }, 38 | () => Series.Highest(source.GetHighPrices(Context).AsReadOnly(), Period)); 39 | var low = Context.GetData("Lowest", new[] { Period.ToString(CultureInfo.InvariantCulture), source.CacheName }, 40 | () => Series.Lowest(source.GetLowPrices(Context).AsReadOnly(), Period)); 41 | var bars = source.Bars; 42 | var list = Context?.GetArray(bars.Count) ?? new double[bars.Count]; 43 | for (int i = 0; i < bars.Count; i++) 44 | { 45 | var hl = high[i] - low[i]; 46 | var stochK = hl == 0 ? 0 : 100 * (bars[i].Close - low[i]) / hl; 47 | list[i] = stochK; 48 | } 49 | return list; 50 | } 51 | 52 | public IContext Context { get; set; } 53 | } 54 | 55 | [HandlerCategory(HandlerCategories.Indicators)] 56 | //[HandlerName("StochRSI")] 57 | [HelperName("Stoch RSI", Language = Constants.En)] 58 | [HelperName("Stoch RSI", Language = Constants.Ru)] 59 | [InputsCount(1)] 60 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 61 | [OutputsCount(1)] 62 | [OutputType(TemplateTypes.DOUBLE)] 63 | [Description("Стохастик от индекса относительной силы. StochRSI = (Текущее значение RSI - Минимальное значение RSI за период) / (Максимальное значение RSI за период - Минимальное значение RSI за период) * 100.")] 64 | [HelperDescription("Stochastics based on relative strength index. StochRSI = (Current RSI - period minimum RSI) / (Period maximum RSI - period minimum RSI) * 100.", Constants.En)] 65 | [SuppressMessage("StyleCopPlus.StyleCopPlusRules", "SP0100:AdvancedNamingRules", Justification = "Reviewed. Suppression is OK here.")] 66 | public sealed class StochRSI : BasePeriodIndicatorHandler, IBar2DoubleHandler, IContextUses 67 | { 68 | public IList Execute(ISecurity source) 69 | { 70 | var rsi = Context.GetData("RSI", new[] { Period.ToString(CultureInfo.InvariantCulture), source.CacheName }, 71 | () => Series.RSI(source.GetClosePrices(Context).AsReadOnly(), Period)); 72 | var high = Series.Highest(rsi.AsReadOnly(), Period, Context); 73 | var low = Series.Lowest(rsi.AsReadOnly(), Period, Context); 74 | var list = Context?.GetArray(rsi.Count) ?? new double[rsi.Count]; 75 | for (int i = 0; i < rsi.Count; i++) 76 | { 77 | var hl = high[i] - low[i]; 78 | var stochRSI = hl == 0 ? 0 : 100 * (rsi[i] - low[i]) / hl; 79 | list[i] = stochRSI; 80 | } 81 | Context?.ReleaseArray((Array)high); 82 | Context?.ReleaseArray((Array)low); 83 | return list; 84 | } 85 | 86 | public IContext Context { get; set; } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Indicators/SumForTimeFrameHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using TSLab.DataSource; 6 | using TSLab.Script.Handlers.Options; 7 | 8 | namespace TSLab.Script.Handlers 9 | { 10 | // TODO: у этого кубика нет описания. Судя по коду что-то вроде "сумма значений в пределах указанного таймфрейма" 11 | [HandlerCategory(HandlerCategories.Indicators)] 12 | [HelperName("Sum for time frame", Language = Constants.En)] 13 | [HelperName("Сумма за таймфрейм", Language = Constants.Ru)] 14 | [InputsCount(1)] 15 | [Input(0, TemplateTypes.DOUBLE)] 16 | [OutputsCount(1)] 17 | [OutputType(TemplateTypes.DOUBLE)] 18 | [Description("Сумма за таймфрейм")] 19 | [HelperDescription("Sum for time frame", Constants.En)] 20 | public sealed class SumForTimeFrameHandler : IDoubleStreamAndValuesHandler 21 | { 22 | public IContext Context { get; set; } 23 | 24 | public bool IsGapTolerant => true; 25 | 26 | /// 27 | /// \~english Timeframe (format D.HH:MM:SS) 28 | /// \~russian Интервал (формат Д.ЧЧ:ММ:СС) 29 | /// 30 | [HelperName("Timeframe", Constants.En)] 31 | [HelperName("Интервал", Constants.Ru)] 32 | [Description("Интервал (формат Д.ЧЧ:ММ:СС)")] 33 | [HelperDescription("Timeframe (format D.HH:MM:SS)", Constants.En)] 34 | [HandlerParameter(true, "1:0:0", Min = "0:0:0", Max = "365.0:0:0", Step = "0:1:0", EditorMin = "0:0:0", EditorMax = "365.0:0:0")] 35 | public TimeSpan TimeFrame { get; set; } 36 | 37 | private DateTime m_firstDateTime; 38 | private DateTime m_lastDateTime; 39 | private double m_sum; 40 | private int m_index = -1; 41 | 42 | public IList Execute(IList values) 43 | { 44 | var security = Context.Runtime.Securities.First(); 45 | var bars = security.Bars; 46 | var count = Math.Min(bars.Count, values.Count); 47 | 48 | if (count == 0) 49 | return new ConstList(values.Count, 0); 50 | 51 | var results = Context?.GetArray(values.Count) ?? new double[values.Count]; 52 | TimeFrameUtils.GetFirstBounds(TimeFrame, bars[0].Date, out var firstDateTime, out var lastDateTime); 53 | var sum = 0D; 54 | 55 | for (var i = 0; i < count; i++) 56 | { 57 | var barDate = bars[i].Date; 58 | if (barDate >= lastDateTime) 59 | { 60 | TimeFrameUtils.GetBounds(TimeFrame, barDate, ref firstDateTime, ref lastDateTime); 61 | sum = 0; 62 | } 63 | results[i] = sum += values[i]; 64 | } 65 | for (var i = count; i < results.Length; i++) 66 | results[i] = sum; 67 | 68 | return results; 69 | } 70 | 71 | public double Execute(double value, int index) 72 | { 73 | if (index < m_index) 74 | throw new InvalidOperationException(); 75 | 76 | if (index == m_index) 77 | return m_sum; 78 | 79 | var security = Context.Runtime.Securities.First(); 80 | var bars = security.Bars; 81 | var count = Math.Min(bars.Count, index + 1); 82 | 83 | if (count == 0) 84 | return 0; 85 | 86 | if (m_firstDateTime == default(DateTime)) 87 | TimeFrameUtils.GetFirstBounds(TimeFrame, bars[index].Date, out m_firstDateTime, out m_lastDateTime); 88 | 89 | for (var i = m_index + 1; i < count; i++) 90 | { 91 | var barDate = bars[i].Date; 92 | if (barDate >= m_lastDateTime) 93 | { 94 | TimeFrameUtils.GetBounds(TimeFrame, barDate, ref m_firstDateTime, ref m_lastDateTime); 95 | m_sum = 0; 96 | } 97 | m_sum += value; 98 | } 99 | m_index = index; 100 | return m_sum; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Indicators/Trix.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | 5 | using TSLab.Script.Handlers.Options; 6 | using TSLab.Script.Helpers; 7 | 8 | // ReSharper disable InconsistentNaming 9 | namespace TSLab.Script.Handlers 10 | { 11 | [HandlerCategory(HandlerCategories.Indicators)] 12 | [HelperName("TRIX", Language = Constants.En)] 13 | [HelperName("TRIX", Language = Constants.Ru)] 14 | [InputsCount(1)] 15 | [Input(0, TemplateTypes.DOUBLE)] 16 | [OutputsCount(1)] 17 | [OutputType(TemplateTypes.DOUBLE)] 18 | [Description("Тройное экспоненциальное скользящее.")] 19 | [HelperDescription("The Triple Exponential Average.", Constants.En)] 20 | public sealed class TRIX : DoubleStreamAndValuesHandlerWithPeriod 21 | { 22 | private double m_lastEma3; 23 | private EMA m_ema1; 24 | private EMA m_ema2; 25 | private EMA m_ema3; 26 | 27 | public override bool IsGapTolerant 28 | { 29 | get { return IsSimple; } 30 | } 31 | 32 | public override IList Execute(IList source) 33 | { 34 | if (source == null) 35 | throw new ArgumentNullException(nameof(source)); 36 | 37 | IList ema3; 38 | if (IsSimple) 39 | ema3 = source; 40 | else 41 | { 42 | var ema1 = Series.EMA(source.AsReadOnly(), Period, Context); 43 | var ema2 = Series.EMA(ema1.AsReadOnly(), Period, Context); 44 | Context?.ReleaseArray((Array)ema1); 45 | ema3 = Series.EMA(ema2.AsReadOnly(), Period, Context); 46 | Context?.ReleaseArray((Array)ema2); 47 | } 48 | 49 | var result = Context?.GetArray(source.Count) ?? new double[source.Count]; 50 | for (var i = 1; i < result.Length; i++) 51 | { 52 | var lastEma3 = ema3[i - 1]; 53 | result[i] = lastEma3 != 0 ? (ema3[i] - lastEma3) / lastEma3 : 0; 54 | } 55 | 56 | if (!IsSimple) 57 | Context?.ReleaseArray((Array)ema3); 58 | return result; 59 | } 60 | 61 | protected override void InitExecuteContext() 62 | { 63 | m_lastEma3 = 0; 64 | if (IsSimple) 65 | return; 66 | 67 | m_ema1 = new EMA { Context = Context, Period = Period }; 68 | m_ema2 = new EMA { Context = Context, Period = Period }; 69 | m_ema3 = new EMA { Context = Context, Period = Period }; 70 | } 71 | 72 | protected override void ClearExecuteContext() 73 | { 74 | m_lastEma3 = 0; 75 | m_ema1 = null; 76 | m_ema2 = null; 77 | m_ema3 = null; 78 | } 79 | 80 | protected override void InitForGap() 81 | { 82 | if (IsSimple) 83 | m_lastEma3 = m_executeContext.GetSourceForGap(m_executeContext.Index - 1); 84 | else 85 | { 86 | var firstIndex = Math.Max(m_executeContext.LastIndex + 1, m_executeContext.Index - 4 * Period); 87 | for (var i = firstIndex; i < m_executeContext.Index; i++) 88 | { 89 | var source = m_executeContext.GetSourceForGap(i); 90 | var ema1 = m_ema1.Execute(source, i); 91 | var ema2 = m_ema2.Execute(ema1, i); 92 | var ema3 = m_ema3.Execute(ema2, i); 93 | m_lastEma3 = ema3; 94 | } 95 | } 96 | } 97 | 98 | protected override double Execute() 99 | { 100 | double ema3; 101 | if (IsSimple) 102 | ema3 = m_executeContext.Source; 103 | else 104 | { 105 | var ema1 = m_ema1.Execute(m_executeContext.Source, m_executeContext.Index); 106 | var ema2 = m_ema2.Execute(ema1, m_executeContext.Index); 107 | ema3 = m_ema3.Execute(ema2, m_executeContext.Index); 108 | } 109 | var result = m_lastEma3 != 0 ? (ema3 - m_lastEma3) / m_lastEma3 : 0; 110 | m_lastEma3 = ema3; 111 | return result; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Other/EmptyDoubleHandler.cs: -------------------------------------------------------------------------------- 1 | namespace TSLab.Script.Handlers 2 | { 3 | [HandlerInvisible] 4 | [OutputType(TemplateTypes.DOUBLE)] 5 | public sealed class EmptyDoubleHandler : IHandler 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Other/TEST.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TSLab-Dev/Handlers/7bb483dce9ac034057762f73752236ff65e021f9/Other/TEST.cs -------------------------------------------------------------------------------- /PortfolioHandlers/AgentHandlers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using TSLab.Script.Handlers.Options; 4 | using TSLab.Utils; 5 | 6 | namespace TSLab.Script.Handlers.PortfolioHandlers 7 | { 8 | public interface IAgentTradingInfoService 9 | { 10 | double GetAgentLots(string symbol); 11 | } 12 | 13 | [HandlerCategory(HandlerCategories.Portfolio)] 14 | [HelperName("Agents lots", Language = Constants.En)] 15 | [InputsCount(1)] 16 | [Input(0, TemplateTypes.SECURITY, Name = "SECURITYSource")] 17 | [OutputsCount(1)] 18 | [OutputType(TemplateTypes.DOUBLE)] 19 | #if !DEBUG 20 | [HandlerInvisible] 21 | #endif 22 | public class AgentHandlers : IStreamHandler 23 | { 24 | 25 | public IList Execute(ISecurity source) 26 | { 27 | var value = 0.0; 28 | var symbol = source?.Symbol; 29 | if (!string.IsNullOrEmpty(symbol)) 30 | { 31 | var service = Locator.Current.GetInstance(); 32 | value = service.GetAgentLots(symbol); 33 | } 34 | return Enumerable.Repeat(value, source.Bars.Count).ToList(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /PortfolioHandlers/Portfolio.Enums.cs: -------------------------------------------------------------------------------- 1 | using TSLab.Utils; 2 | 3 | namespace TSLab.Script.Handlers 4 | { 5 | public enum PositionField 6 | { 7 | [LocalizeDescription("PositionField.RealRest")] // Текущая 8 | RealRest, 9 | [LocalizeDescription("PositionField.IncomeRest")] // Входящая 10 | IncomeRest, 11 | [LocalizeDescription("PositionField.PlanRest")] // Плановая 12 | PlanRest, 13 | [LocalizeDescription("PositionField.BalancePrice")] // Учетная цена 14 | BalancePrice, 15 | [LocalizeDescription("PositionField.AssessedPrice")] // Оценочная цена 16 | AssessedPrice, 17 | [LocalizeDescription("PositionField.Commission")] // Комиссия 18 | Commission, 19 | [LocalizeDescription("PositionField.Balance")] // Чистая стоимость 20 | Balance, 21 | [LocalizeDescription("PositionField.BalForwardVolume")] // Учетная стоимость 22 | BalForwardVolume, 23 | [LocalizeDescription("PositionField.ProfitVolume")] // НП/У 24 | ProfitVolume, 25 | [LocalizeDescription("PositionField.DailyPl")] // П/У (дн) 26 | DailyPl, 27 | [LocalizeDescription("PositionField.VarMargin")] // Вар.маржа 28 | VarMargin, 29 | } 30 | 31 | public enum AgentField 32 | { 33 | [LocalizeDescription("AgentField.Profit")] // П/У 34 | Profit, 35 | 36 | [LocalizeDescription("AgentField.DailyProfit")] // П/У (дн) 37 | DailyProfit, 38 | 39 | [LocalizeDescription("AgentField.ProfitVol")] // НП/У 40 | ProfitVol, 41 | 42 | [LocalizeDescription("AgentField.PositionInLots")] // Позиция (лоты) 43 | PositionInLots, 44 | 45 | [LocalizeDescription("AgentField.PositionInMoney")] // Позиция (деньги) 46 | PositionInMoney, 47 | 48 | [LocalizeDescription("AgentField.PositionLong")] // Длинная поз.(лоты) 49 | PositionLong, 50 | 51 | [LocalizeDescription("AgentField.PositionShort")] // Короткая поз.(лоты) 52 | PositionShort, 53 | 54 | [LocalizeDescription("AgentField.AssessedPrice")] // Оценочная цена 55 | AssessedPrice, 56 | 57 | [LocalizeDescription("AgentField.BalancePrice")] // Учетная цена 58 | BalancePrice, 59 | 60 | [LocalizeDescription("AgentField.LastPrice")] // Текущая цена 61 | LastPrice, 62 | 63 | [LocalizeDescription("AgentField.Commission")] // Комиссия 64 | Commission, 65 | 66 | [LocalizeDescription("AgentField.Slippage")] // Проскальзывание 67 | Slippage, 68 | 69 | [LocalizeDescription("AgentField.SlippagePercent")] // Проскальзывание % 70 | SlippagePercent, 71 | } 72 | 73 | public enum ProfitKind 74 | { 75 | [LocalizeDescription("ProfitKind.Unfixed")] 76 | Unfixed, 77 | [LocalizeDescription("ProfitKind.Fixed")] 78 | Fixed, 79 | [LocalizeDescription("ProfitKind.MaxFixed")] 80 | MaxFixed, 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Position/HoldSignalForNBars.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using TSLab.Script.Handlers.Options; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | [HandlerCategory(HandlerCategories.Position)] 10 | [HelperName("Hold signal for N bars", Language = Constants.En)] 11 | [HelperName("Удерживать сигнал N баров", Language = Constants.Ru)] 12 | [InputsCount(1)] 13 | [Input(0, TemplateTypes.BOOL)] 14 | [OutputsCount(1)] 15 | [OutputType(TemplateTypes.BOOL)] 16 | [Description("Удерживает сигнал 'Истина' в течение заданного количества баров после его появления.")] 17 | [HelperDescription("Holds a signal TRUE for some number of bars.", Constants.En)] 18 | public sealed class HoldSignalForNBars : IStreamHandler, IValuesHandlerWithNumber, IOneSourceHandler, IBooleanReturns, IBooleanInputs 19 | { 20 | private int m_lastTrueIndex = -1; 21 | 22 | /// 23 | /// \~english Hold signal for N bars 24 | /// \~russian Удерживать сигнал в течение N баров 25 | /// 26 | [HelperName("Bars count", Constants.En)] 27 | [HelperName("Количество баров", Constants.Ru)] 28 | [Description("Количество баров для продления сигнала")] 29 | [HelperDescription("Bars count to hold a signal", Constants.En)] 30 | [HandlerParameter(true, "0", Min = "0", Max = "10", Step = "1", EditorMin = "0")] 31 | public int NBars { get; set; } 32 | 33 | public IList Execute(IList source) 34 | { 35 | if (NBars <= 0 || source.Count <= 1 || source.All(item => item) || source.All(item => !item)) 36 | return source; 37 | 38 | var result = new List(source); 39 | for (var i = 0; i < source.Count; i++) 40 | { 41 | if (source[i]) 42 | { 43 | var jMax = Math.Min(i + NBars, source.Count - 1); 44 | for (var j = i + 1; j <= jMax; j++) 45 | result[j] = true; 46 | } 47 | } 48 | return result; 49 | } 50 | 51 | public bool Execute(bool value, int barIndex) 52 | { 53 | if (value) 54 | { 55 | m_lastTrueIndex = barIndex; 56 | return true; 57 | } 58 | return barIndex >= m_lastTrueIndex && barIndex <= m_lastTrueIndex + NBars; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sources of the built-in TSLab handlers 2 | 3 | Исходные файлы встроенных TSLab обработчиков -------------------------------------------------------------------------------- /ScriptCommonHandlers.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | TSLab 6 | TSLab 7 | TSLab 8 | TSLab.Script.Handlers 9 | TSLab.Script.Handlers 10 | 3.0.0 11 | false 12 | 13 | 14 | 15 | true 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Service/ControlMessageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using TSLab.Script.Handlers.Options; 5 | using TSLab.Script.Optimization; 6 | 7 | // ReSharper disable once CheckNamespace 8 | namespace TSLab.Script.Handlers 9 | { 10 | [HandlerCategory(HandlerCategories.ServiceElements)] 11 | [HelperName("Control message", Language = Constants.En)] 12 | [HelperName("Контрольное сообщение", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.BOOL)] 15 | [OutputsCount(0)] 16 | [Description("Выводит контрольное сообщение")] 17 | [HelperDescription("Outputs control message", Constants.En)] 18 | public sealed class ControlMessageHandler : IOneSourceHandler, IBooleanReturns, IStreamHandler, IValuesHandlerWithNumber, IBooleanInputs, IContextUses, ICustomListValues 19 | { 20 | public IContext Context { get; set; } 21 | 22 | /// 23 | /// \~english True message 24 | /// \~russian Истинное сообщение 25 | /// 26 | [HelperName("True message", Constants.En)] 27 | [HelperName("Истинное сообщение", Constants.Ru)] 28 | [Description("Истинное сообщение")] 29 | [HelperDescription("True message", Constants.En)] 30 | [HandlerParameter(true, "")] 31 | public string TrueMessage { get; set; } 32 | 33 | /// 34 | /// \~english False message 35 | /// \~russian Ложное сообщение 36 | /// 37 | [HelperName("False message", Constants.En)] 38 | [HelperName("Ложное сообщение", Constants.Ru)] 39 | [Description("Ложное сообщение")] 40 | [HelperDescription("False message", Constants.En)] 41 | [HandlerParameter(true, "")] 42 | public string FalseMessage { get; set; } 43 | 44 | /// 45 | /// \~english Message 46 | /// \~russian Сообщение 47 | /// 48 | [HelperName("Message", Constants.En)] 49 | [HelperName("Сообщение", Constants.Ru)] 50 | [Description("Сообщение")] 51 | [HelperDescription("Message", Constants.En)] 52 | [HandlerParameter(true, "", IsCalculable = true)] 53 | public StringOptimProperty Message { get; set; } 54 | 55 | public void Execute(IList values) 56 | { 57 | if (values == null) 58 | throw new ArgumentNullException(nameof(values)); 59 | 60 | if (values.Count > 0) 61 | Message.Value = values[values.Count - 1] ? TrueMessage : FalseMessage; 62 | else 63 | Message.Value = string.Empty; 64 | } 65 | 66 | public void Execute(bool value, int number) 67 | { 68 | if (number == Context.BarsCount - (Context.IsLastBarUsed ? 1 : 2)) 69 | Message.Value = value ? TrueMessage : FalseMessage; 70 | } 71 | 72 | public IEnumerable GetValuesForParameter(string paramName) 73 | { 74 | yield return TrueMessage; 75 | yield return FalseMessage; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Service/EventKindHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using TSLab.Script.Handlers.Options; 6 | using TSLab.Utils; 7 | 8 | // ReSharper disable once CheckNamespace 9 | namespace TSLab.Script.Handlers 10 | { 11 | public enum EventKind 12 | { 13 | [LocalizeDescription(nameof(EventKind) + "." + nameof(None))] 14 | None, 15 | [LocalizeDescription(nameof(EventKind) + "." + nameof(OrderRejected))] 16 | OrderRejected, 17 | [LocalizeDescription(nameof(EventKind) + "." + nameof(OrderFilled))] 18 | OrderFilled, 19 | [LocalizeDescription(nameof(EventKind) + "." + nameof(PositionOpening))] 20 | PositionOpening, 21 | [LocalizeDescription(nameof(EventKind) + "." + nameof(PositionClosing))] 22 | PositionClosing, 23 | [LocalizeDescription(nameof(EventKind) + "." + nameof(OrderQtyChanged))] 24 | OrderQtyChanged, 25 | [LocalizeDescription(nameof(EventKind) + "." + nameof(TradingIsStarted))] 26 | TradingIsStarted, 27 | [LocalizeDescription(nameof(EventKind) + "." + nameof(TradingIsStopped))] 28 | TradingIsStopped, 29 | [LocalizeDescription(nameof(EventKind) + "." + nameof(OrderCanceled))] 30 | OrderCanceled, 31 | [LocalizeDescription(nameof(EventKind) + "." + nameof(PretradeLimitation))] 32 | PretradeLimitation, 33 | } 34 | 35 | [HandlerCategory(HandlerCategories.ServiceElements)] 36 | [HelperName("Event", Language = Constants.En)] 37 | [HelperName("Событие", Language = Constants.Ru)] 38 | [InputsCount(1)] 39 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 40 | [OutputsCount(1)] 41 | [OutputType(TemplateTypes.BOOL)] 42 | [Description("Событие")] 43 | [HelperDescription("Event", Constants.En)] 44 | public sealed class EventKindHandler : IOneSourceHandler, IStreamHandler, ISecurityInputs, IContextUses 45 | { 46 | private static readonly IReadOnlyDictionary s_eventKindToNameMap = ((EventKind[])Enum.GetValues(typeof(EventKind))).ToDictionary(item => item, item => item.ToString()); 47 | 48 | public IContext Context { get; set; } 49 | 50 | /// 51 | /// \~english Event kind 52 | /// \~russian Вид события 53 | /// 54 | [HelperName("Event kind", Constants.En)] 55 | [HelperName("Вид события", Constants.Ru)] 56 | [Description("Вид события")] 57 | [HelperDescription("Event kind", Constants.En)] 58 | [HandlerParameter(true, nameof(EventKind.None))] 59 | public EventKind EventKind { get; set; } 60 | 61 | public IList Execute(ISecurity source) 62 | { 63 | var strEventKind = s_eventKindToNameMap[EventKind]; 64 | var sourceSecurityDescriptionId = source.SecurityDescription.Id; 65 | var result = Context.Runtime.LastRecalcReasons.Any(item => item.Name == strEventKind && item.DataSourceSecurity.Id == sourceSecurityDescriptionId); 66 | return new ConstList(source.Bars.Count, result); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Service/ExportValuesHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using TSLab.DataSource; 4 | using TSLab.Utils; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace TSLab.Script.Handlers 8 | { 9 | [HandlerCategory(HandlerCategories.ServiceElements)] 10 | [OutputsCount(0)] 11 | public sealed class ExportValuesHandler : ITwoSourcesHandler, ISecurityInput0, IBooleanInput1, IDoubleInput1, IIntInput1, IStreamHandler, IValuesHandlerWithNumber, IContextUses 12 | { 13 | private bool[] m_boolValues; 14 | private double[] m_doubleValues; 15 | private int[] m_intValues; 16 | 17 | public IContext Context { get; set; } 18 | 19 | [HandlerParameter(true, "")] 20 | public string Id { get; set; } 21 | 22 | public void Execute(ISecurity security, IList values) 23 | { 24 | Export(security, values); 25 | } 26 | 27 | public void Execute(ISecurity security, IList values) 28 | { 29 | Export(security, values); 30 | } 31 | 32 | public void Execute(ISecurity security, IList values) 33 | { 34 | Export(security, values); 35 | } 36 | 37 | public void Execute(ISecurity security, bool value, int index) 38 | { 39 | Execute(security, value, index, ref m_boolValues); 40 | } 41 | 42 | public void Execute(ISecurity security, double value, int index) 43 | { 44 | Execute(security, value, index, ref m_doubleValues); 45 | } 46 | 47 | public void Execute(ISecurity security, int value, int index) 48 | { 49 | Execute(security, value, index, ref m_intValues); 50 | } 51 | 52 | private void Execute(ISecurity security, T value, int index, ref T[] values) 53 | { 54 | var barsCount = security.Bars.Count; 55 | (values ?? (values = new T[barsCount]))[index] = value; 56 | 57 | if (index == barsCount - 1) 58 | Export(security, values); 59 | } 60 | 61 | private void Export(ISecurity security, IList values) 62 | { 63 | if (Context.IsOptimization) 64 | return; 65 | 66 | var bars = security.Bars; 67 | var count = Math.Min(bars.Count, values.Count); 68 | var dateTimes = new DateTime[count]; 69 | 70 | for (var i = 0; i < count; i++) 71 | dateTimes[i] = bars[i].Date; 72 | 73 | Context.StoreGlobalObject(Id, new NotClearableContainer(new Tuple, IList>(dateTimes, values))); 74 | } 75 | 76 | public IEnumerable GetValuesForParameter(string paramName) 77 | { 78 | if (paramName.EqualsIgnoreCase(nameof(Id))) 79 | return new[] { Id ?? "" }; 80 | return new[] { "" }; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Service/HeartbeatHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using TSLab.Script.Handlers.Options; 4 | 5 | // ReSharper disable once CheckNamespace 6 | namespace TSLab.Script.Handlers 7 | { 8 | [HandlerCategory(HandlerCategories.ServiceElements)] 9 | [HelperName("Метроном 2", Language = Constants.Ru)] 10 | [HelperName("Heartbeat 2", Language = Constants.En)] 11 | [HandlerAlwaysKeep] 12 | [OutputsCount(0)] 13 | [Description("Метроном 2")] 14 | [HelperDescription("Heartbeat 2", Constants.En)] 15 | public sealed class HeartbeatHandler : IHandler, IZeroSourceHandler, IContextUses, INeedVariableId, INeedVariableName 16 | { 17 | public IContext Context { get; set; } 18 | public string VariableId { get; set; } 19 | public string VariableName { get; set; } 20 | 21 | [HelperName("Интервал", Constants.Ru)] 22 | [HelperName("Interval", Constants.En)] 23 | [Description("Интервал")] 24 | [HelperDescription("Interval", Language = Constants.En)] 25 | [HandlerParameter(true, "0:1:0", Min = "0:0:0", Max = "1.0:0:0", Step = "0:0:1", EditorMin = "0:0:0", EditorMax = "1.0:0:0")] 26 | public TimeSpan Interval { get; set; } 27 | 28 | public void Execute() 29 | { 30 | if (!Context.IsOptimization) 31 | HeartbeatManager.Instance.Register(this); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Service/HeartbeatManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using TSLab.Utils; 7 | 8 | // ReSharper disable once CheckNamespace 9 | namespace TSLab.Script.Handlers 10 | { 11 | internal sealed class HeartbeatManager 12 | { 13 | private sealed class Context 14 | { 15 | public IRuntime Runtime { get; set; } 16 | public string VariableId { get; set; } 17 | public string VariableName { get; set; } 18 | public TimeSpan Interval { get; set; } 19 | public DateTime CheckTime { get; set; } 20 | public bool IsBusy { get; set; } 21 | } 22 | 23 | public static readonly HeartbeatManager Instance = new HeartbeatManager(); 24 | private readonly IDictionary m_contextsMap = new Dictionary(); 25 | 26 | private HeartbeatManager() 27 | { 28 | var thread = ThreadProfiler.Create(ThreadStart); 29 | thread.IsBackground = true; 30 | thread.Name = nameof(HeartbeatManager) + "." + nameof(Thread); 31 | thread.Start(); 32 | } 33 | 34 | public void Register(HeartbeatHandler handler) 35 | { 36 | var runtime = handler.Context.Runtime; 37 | var key = string.Join(".", runtime.TradeName, runtime.IsAgentMode, handler.VariableId); 38 | 39 | lock (m_contextsMap) 40 | if (m_contextsMap.TryGetValue(key, out var oldContext)) 41 | { 42 | oldContext.Runtime = runtime; 43 | oldContext.VariableId = handler.VariableId; 44 | oldContext.VariableName = handler.VariableName; 45 | oldContext.Interval = handler.Interval; 46 | } 47 | else 48 | m_contextsMap[key] = new Context 49 | { 50 | Runtime = runtime, 51 | VariableId = handler.VariableId, 52 | VariableName = handler.VariableName, 53 | Interval = handler.Interval, 54 | }; 55 | } 56 | 57 | private void ThreadStart() 58 | { 59 | while (true) 60 | { 61 | Thread.Sleep(1); 62 | var utcNow = DateTime.UtcNow; 63 | 64 | lock (m_contextsMap) 65 | foreach (var keyValuePair in m_contextsMap.ToArray()) 66 | { 67 | var context = keyValuePair.Value; 68 | var runtime = context.Runtime; 69 | 70 | if (runtime.IsDisposedOrDisposing || (runtime.IsAgentMode && !runtime.IsRealTime)) 71 | m_contextsMap.Remove(keyValuePair.Key); 72 | else if (!context.IsBusy && utcNow - context.CheckTime >= context.Interval) 73 | { 74 | if (!runtime.IsAgentMode && !runtime.IsRealTime) 75 | m_contextsMap.Remove(keyValuePair.Key); 76 | else 77 | { 78 | context.CheckTime = utcNow; 79 | context.IsBusy = true; 80 | Task.Factory.StartNew(() => Execute(context)); 81 | } 82 | } 83 | } 84 | } 85 | } 86 | 87 | private static void Execute(Context context) 88 | { 89 | try 90 | { 91 | var runtime = context.Runtime; 92 | if (runtime.IsDisposedOrDisposing) 93 | return; 94 | 95 | runtime.Recalc(RecalcReasons.Heartbeat2, null); 96 | } 97 | catch (Exception ex) 98 | { 99 | if (Logging.On) Logging.Exception(Logging.Handlers, "Heartbeat", ex); 100 | } 101 | finally 102 | { 103 | context.IsBusy = false; 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Service/ImportBoolValuesHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | // ReSharper disable once CheckNamespace 5 | namespace TSLab.Script.Handlers 6 | { 7 | public sealed class ImportBoolValuesHandler : ImportValuesHandler, IBooleanReturns 8 | { 9 | protected override bool GetValue(IReadOnlyList values) 10 | { 11 | if (values.Count == 0) 12 | return default(bool); 13 | 14 | if (values.Count == 1) 15 | return values[0]; 16 | 17 | var trueCount = values.Count(item => item); 18 | return trueCount >= values.Count - trueCount; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Service/ImportDoubleValuesHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | // ReSharper disable once CheckNamespace 5 | namespace TSLab.Script.Handlers 6 | { 7 | public sealed class ImportDoubleValuesHandler : ImportValuesHandler, IDoubleReturns 8 | { 9 | protected override double GetValue(IReadOnlyList values) 10 | { 11 | if (values.Count == 0) 12 | return default(double); 13 | 14 | if (values.Count == 1) 15 | return values[0]; 16 | 17 | return values.Sum() / values.Count; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Service/ImportIntValuesHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | // ReSharper disable once CheckNamespace 5 | namespace TSLab.Script.Handlers 6 | { 7 | public sealed class ImportIntValuesHandler : ImportValuesHandler, IIntReturns 8 | { 9 | protected override int GetValue(IReadOnlyList values) 10 | { 11 | if (values.Count == 0) 12 | return default(int); 13 | 14 | if (values.Count == 1) 15 | return values[0]; 16 | 17 | return values.Sum() / values.Count; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Service/ImportValuesHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using TSLab.DataSource; 4 | using TSLab.Utils; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace TSLab.Script.Handlers 8 | { 9 | [HandlerCategory(HandlerCategories.ServiceElements)] 10 | [InputsCount(1)] 11 | public abstract class ImportValuesHandler : IOneSourceHandler, ISecurityInputs, IStreamHandler, IContextUses 12 | { 13 | public IContext Context { get; set; } 14 | 15 | [HandlerParameter(true, "")] 16 | public string Id { get; set; } 17 | 18 | public IList Execute(ISecurity security) 19 | { 20 | var bars = security.Bars; 21 | var barsCount = bars.Count; 22 | var values = new T[barsCount]; 23 | 24 | if (barsCount == 0 || !(Context.LoadGlobalObject(Id, null)?.Content is Tuple, IList> context)) 25 | return values; 26 | 27 | var importedDateTimes = context.Item1; 28 | var importedValues = context.Item2; 29 | var importedCount = Math.Min(importedDateTimes.Count, importedValues.Count); 30 | 31 | if (importedCount == 0) 32 | return values; 33 | 34 | int index = 0, importedIndex = 0; 35 | var importedDateTime = importedDateTimes[0]; 36 | 37 | while (index < barsCount && bars[index].Date < importedDateTime) 38 | values[index++] = default(T); 39 | 40 | var currentValues = new List(); 41 | while (index < barsCount && importedIndex < importedCount) 42 | { 43 | importedDateTime = importedDateTimes[importedIndex]; 44 | var barDate = bars[index].Date; 45 | 46 | if (importedDateTime <= barDate) 47 | currentValues.Add(importedValues[importedIndex++]); 48 | else 49 | { 50 | var value1 = GetValue(currentValues); 51 | while (index < barsCount && bars[index].Date < importedDateTime) 52 | values[index++] = value1; 53 | 54 | currentValues.Clear(); 55 | } 56 | } 57 | var value2 = GetValue(currentValues); 58 | while (index < barsCount) 59 | values[index++] = value2; 60 | 61 | return values; 62 | } 63 | 64 | protected abstract T GetValue(IReadOnlyList values); 65 | 66 | public IEnumerable GetValuesForParameter(string paramName) 67 | { 68 | if (paramName.EqualsIgnoreCase(nameof(Id))) 69 | return new[] { Id ?? "" }; 70 | return new[] { "" }; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Service/InstrumentByName.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | using TSLab.Script.Handlers.Options; 5 | using TSLab.Utils; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | [HandlerCategory(HandlerCategories.ServiceElements)] 10 | [HelperName("Instrument by name", Language = Constants.En)] 11 | [HelperName("Инструмент по имени", Language = Constants.Ru)] 12 | [InputsCount(1)] 13 | [Input(0, TemplateTypes.MULTI_SECURITY, Name = Constants.SecuritySource)] 14 | [OutputsCount(1)] 15 | [OutputType(TemplateTypes.SECURITY)] 16 | [Description("Найти инструмент по имени в мульти-источнике. " + 17 | "Если инструмент не найден по имени, то возвращает первый по списку.")] 18 | [HelperDescription("Find the instrument by name in the multi-source. " + 19 | "If the instrument is not found by name, it returns the first one in the list.", Constants.En)] 20 | [NotCacheable] 21 | public class InstrumentByName : IStreamHandler, ISecurityReturns, ICustomListValues 22 | { 23 | [HelperName("Name", Constants.En)] 24 | [HelperName("Название", Constants.Ru)] 25 | [HandlerParameter(true, "")] 26 | public string Name { get; set; } 27 | 28 | private string[] m_names; 29 | 30 | public ISecurity Execute(ISecurity[] securities) 31 | { 32 | m_names = securities.Select(x => x.Symbol).ToArray(); 33 | return securities.FirstOrDefault(x => x.Symbol.ContainsIgnoreCase(Name)) ?? securities.First(); 34 | } 35 | 36 | public IEnumerable GetValuesForParameter(string paramName) 37 | { 38 | if (paramName.EqualsIgnoreCase(nameof(Name))) 39 | return m_names ?? new[] { "" }; 40 | return new[] { "" }; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Service/InstrumentByNumber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using TSLab.Script.Handlers.Options; 4 | using TSLab.Utils; 5 | 6 | namespace TSLab.Script.Handlers 7 | { 8 | [HandlerCategory(HandlerCategories.ServiceElements)] 9 | [HelperName("Instrument by number", Language = Constants.En)] 10 | [HelperName("Инструмент по нореру", Language = Constants.Ru)] 11 | [InputsCount(1)] 12 | [Input(0, TemplateTypes.MULTI_SECURITY, Name = Constants.SecuritySource)] 13 | [OutputsCount(1)] 14 | [OutputType(TemplateTypes.SECURITY)] 15 | [Description("Найти инструмент по номеру в мульти-источнике.")] 16 | [HelperDescription("Find the instrument by number in the multi-source.", Constants.En)] 17 | [NotCacheable] 18 | public class InstrumentByNumber : IStreamHandler, ISecurityReturns 19 | { 20 | [HelperName("Number", Constants.En)] 21 | [HelperName("Номер", Constants.Ru)] 22 | [HandlerParameter(true, "0")] 23 | public int Number { get; set; } 24 | 25 | public ISecurity Execute(ISecurity[] securities) 26 | { 27 | if (securities.Length > Number) 28 | return securities[Number]; 29 | throw new Exception($"{RM.GetString("SecurityNotFound")}. Securities count: {securities.Length}, number: {Number}"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Service/LoadFromGlobalCache2.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using TSLab.Script.Handlers.Options; 4 | using TSLab.Script.Options; 5 | using TSLab.Utils; 6 | 7 | namespace TSLab.Script.Handlers 8 | { 9 | [HandlerCategory(HandlerCategories.ServiceElements)] 10 | [HelperName("Load from Global Cache", Language = Constants.En)] 11 | [HelperName("Загрузить из Глобального Кеша", Language = Constants.Ru)] 12 | [InputsCount(1)] 13 | [Input(0, TemplateTypes.SECURITY | TemplateTypes.OPTION_SERIES | TemplateTypes.OPTION, Name = Constants.AnyOption)] 14 | [OutputType(TemplateTypes.DOUBLE)] 15 | [Description("Загрузить значение индикатора из Глобального Кеша")] 16 | [HelperDescription("Load indicator from Global Cache", Constants.En)] 17 | public class LoadFromGlobalCache2 : IStreamHandler, IContextUses, ICustomListValues 18 | { 19 | [HelperName("Name", Constants.En)] 20 | [HelperName("Название", Constants.Ru)] 21 | [Description("Уникальное название в Глобальном Кеше")] 22 | [HelperDescription("Unique name in the Global Cache", Language = Constants.En)] 23 | [HandlerParameter(true, "MyCache")] 24 | public string Name { get; set; } 25 | 26 | [HelperName("Load from disk", Constants.En)] 27 | [HelperName("Загружать с диска", Constants.Ru)] 28 | [Description("Загружать значения из файла на диске для повторного использования между перезапусками программы")] 29 | [HelperDescription("Load from HDD to use indicator values across different program sessions", Language = Constants.En)] 30 | [HandlerParameter(true, "true")] 31 | public bool LoadFromStorage { get; set; } 32 | 33 | public IContext Context { get; set; } 34 | 35 | public IList Execute(ISecurity sec) 36 | { 37 | return Load(sec); 38 | } 39 | 40 | public IList Execute(IOption opt) 41 | { 42 | if ((opt == null) || (opt.UnderlyingAsset == null)) 43 | return Constants.EmptyListDouble; 44 | 45 | var res = Execute(opt.UnderlyingAsset); 46 | return res; 47 | } 48 | 49 | public IList Execute(IOptionSeries optSer) 50 | { 51 | if ((optSer == null) || (optSer.UnderlyingAsset == null)) 52 | return Constants.EmptyListDouble; 53 | 54 | var res = Execute(optSer.UnderlyingAsset); 55 | return res; 56 | } 57 | 58 | private IList Load(ISecurity sec) 59 | { 60 | var res = SaveToGlobalCache2.LoadDataByBars(Context, sec, Name, LoadFromStorage); 61 | return res; 62 | } 63 | 64 | public IEnumerable GetValuesForParameter(string paramName) 65 | { 66 | if (paramName.EqualsIgnoreCase(nameof(Name))) 67 | return new[] { Name ?? "" }; 68 | return new[] { "" }; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Service/MessageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using TSLab.Script.Handlers.Options; 6 | 7 | // ReSharper disable once CheckNamespace 8 | namespace TSLab.Script.Handlers 9 | { 10 | [HandlerCategory(HandlerCategories.ServiceElements)] 11 | [HelperName("Message", Language = Constants.En)] 12 | [HelperName("Сообщение", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.BOOL)] 15 | [OutputsCount(0)] 16 | [Description("При появлении на входе блока значения 'Истина' выводит в лог программы пользовательское сообщение.")] 17 | [HelperDescription("When input becomes TRUE a handler sends user message to a TSLab log.", Constants.En)] 18 | public sealed class MessageHandler : IOneSourceHandler, IBooleanReturns, IStreamHandler, IValuesHandlerWithNumber, IBooleanInputs, IContextUses 19 | { 20 | private const string UserMessageTag = "$UserMessageTag"; 21 | private int m_barIndex = -1; 22 | private int m_cycleIndex; 23 | 24 | public IContext Context { get; set; } 25 | 26 | /// 27 | /// \~english Message 28 | /// \~russian Сообщение 29 | /// 30 | [HelperName("Message", Constants.En)] 31 | [HelperName("Сообщение", Constants.Ru)] 32 | [Description("Сообщение")] 33 | [HelperDescription("Message", Constants.En)] 34 | [HandlerParameter(true, "", NotOptimized = true)] 35 | public string Message { get; set; } 36 | 37 | /// 38 | /// \~english Additional user tag 39 | /// \~russian Дополнительная пользовательская метка 40 | /// 41 | [HelperName("Tag", Constants.En)] 42 | [HelperName("Метка", Constants.Ru)] 43 | [Description("Дополнительная пользовательская метка")] 44 | [HelperDescription("Additional user tag", Constants.En)] 45 | [HandlerParameter(true, "Tag", NotOptimized = true)] 46 | public string Tag { get; set; } 47 | 48 | /// 49 | /// \~english Message importance (Info, Warning, Error) 50 | /// \~russian Важность сообщения (Info, Warning, Error) 51 | /// 52 | [HelperName("Importance", Constants.En)] 53 | [HelperName("Важность", Constants.Ru)] 54 | [Description("Важность сообщения (Info, Warning, Error)")] 55 | [HelperDescription("Message importance (Info, Warning, Error)", Constants.En)] 56 | [HandlerParameter(true, "Info", NotOptimized = true)] 57 | public MessageType Type { get; set; } 58 | 59 | public bool IsInCycle { get; set; } 60 | 61 | public void Execute(IList values) 62 | { 63 | if (values == null) 64 | throw new ArgumentNullException(nameof(values)); 65 | 66 | if (values.LastOrDefault()) 67 | Log(Message); 68 | } 69 | 70 | public void Execute(bool value, int barIndex) 71 | { 72 | if (IsInCycle) 73 | { 74 | if (m_barIndex != barIndex) 75 | { 76 | m_barIndex = barIndex; 77 | m_cycleIndex = 0; 78 | } 79 | else 80 | m_cycleIndex++; 81 | } 82 | if (value && barIndex == Context.BarsCount - (Context.IsLastBarUsed ? 1 : 2)) 83 | Log(IsInCycle ? $"{Message} ({m_cycleIndex})" : Message); 84 | } 85 | 86 | public void Execute(IReadOnlyList> listOfLists) 87 | { 88 | if (listOfLists == null) 89 | throw new ArgumentNullException(nameof(listOfLists)); 90 | 91 | if (listOfLists.Count == 0) 92 | return; 93 | 94 | var lastList = listOfLists.Last(); 95 | var indexes = new List(lastList.Count); 96 | 97 | for (var i = 0; i < lastList.Count; i++) 98 | if (lastList[i]) 99 | indexes.Add(i); 100 | 101 | if (indexes.Count > 0) 102 | Log($"{Message} ({string.Join(", ", indexes)})"); 103 | } 104 | 105 | private void Log(string message) 106 | { 107 | var args = new Dictionary { { UserMessageTag, Tag ?? string.Empty } }; 108 | Context.Log(message, Type, true, args); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Service/TimestampHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using TSLab.Utils; 4 | 5 | // ReSharper disable once CheckNamespace 6 | namespace TSLab.Script.Handlers 7 | { 8 | [HandlerCategory(HandlerCategories.ServiceElements)] 9 | public sealed class TimestampHandler : IBar2DoubleHandler, IContextUses 10 | { 11 | public IContext Context { get; set; } 12 | 13 | public IList Execute(ISecurity source) 14 | { 15 | if (source == null) 16 | throw new ArgumentNullException(nameof(source)); 17 | 18 | var bars = source.Bars; 19 | var barsCount = bars.Count; 20 | 21 | if (barsCount == 0) 22 | return EmptyArrays.Double; 23 | 24 | var results = Context.GetArray(barsCount); 25 | for (var i = 0; i < barsCount; i++) 26 | results[i] = new DateTimeOffset(bars[i].Date).ToUnixTimeMilliseconds(); 27 | 28 | return results; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /ShrinkedList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace TSLab.Script.Handlers 6 | { 7 | public sealed class ShrinkedList : IList 8 | { 9 | private readonly List m_list; 10 | 11 | public ShrinkedList(int capacity) 12 | { 13 | if (capacity < 1) 14 | throw new ArgumentOutOfRangeException(nameof(capacity)); 15 | 16 | m_list = new List(capacity); 17 | } 18 | 19 | public IEnumerator GetEnumerator() 20 | { 21 | return m_list.GetEnumerator(); 22 | } 23 | 24 | IEnumerator IEnumerable.GetEnumerator() 25 | { 26 | return m_list.GetEnumerator(); 27 | } 28 | 29 | public void Add(T item) 30 | { 31 | if (m_list.Count == m_list.Capacity) 32 | m_list.RemoveAt(0); 33 | 34 | m_list.Add(item); 35 | } 36 | 37 | public void Clear() 38 | { 39 | m_list.Clear(); 40 | } 41 | 42 | public bool Contains(T item) 43 | { 44 | return m_list.Contains(item); 45 | } 46 | 47 | public void CopyTo(T[] array, int arrayIndex) 48 | { 49 | m_list.CopyTo(array, arrayIndex); 50 | } 51 | 52 | public bool Remove(T item) 53 | { 54 | return m_list.Remove(item); 55 | } 56 | 57 | public int Count 58 | { 59 | get { return m_list.Count; } 60 | } 61 | 62 | public bool IsReadOnly 63 | { 64 | get { return ((IList)m_list).IsReadOnly; } 65 | } 66 | 67 | public int IndexOf(T item) 68 | { 69 | return m_list.IndexOf(item); 70 | } 71 | 72 | public void Insert(int index, T item) 73 | { 74 | m_list.Insert(index, item); 75 | } 76 | 77 | public void RemoveAt(int index) 78 | { 79 | m_list.RemoveAt(index); 80 | } 81 | 82 | public T this[int index] 83 | { 84 | get { return m_list[index]; } 85 | set { m_list[index] = value; } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /TSChannel/BoolReceiverHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using TSLab.Script.Handlers.Options; 4 | using TSLab.Utils; 5 | 6 | namespace TSLab.Script.Handlers.TSChannel 7 | { 8 | [HandlerCategory(HandlerCategories.TSChannel)] 9 | [InputsCount(1, 2)] 10 | [Input(0, TemplateTypes.STRING, Name = Constants.SecuritySource)] 11 | [Input(1, TemplateTypes.STRING, Name = "Prefix")] 12 | [OutputsCount(1)] 13 | [OutputType(TemplateTypes.BOOL)] 14 | [NotCacheable] 15 | public class BoolReceiverHandler : ConstGenBase, IStreamHandler, INeedVariableVisual, IContextUses 16 | { 17 | [HandlerParameter(NotOptimized = false)] 18 | public bool Value { get; set; } 19 | 20 | 21 | [HandlerParameter(true, "false")] 22 | public bool DefaultValue { get; set; } 23 | 24 | public IList Execute(IList receiver) 25 | { 26 | return Execute(receiver, null); 27 | } 28 | 29 | public IList Execute(IList receiver, IList prefix) 30 | { 31 | if (receiver.Count == 0) 32 | return Array.Empty(); 33 | 34 | var v = Convert.ToDouble(DefaultValue); 35 | try 36 | { 37 | var service = Locator.Current.GetInstance(); 38 | var pfx = prefix == null ? "" : prefix[0]; 39 | var name = $"{pfx}{VariableVisual}"; 40 | v = service.GetValue(receiver[0], name, v); 41 | } 42 | catch (Exception e) 43 | { 44 | Context.Log(e.Message, MessageType.Error); 45 | } 46 | 47 | var bv = Convert.ToBoolean(v); 48 | MakeList(receiver.Count, bv); 49 | Value = bv; 50 | return this; 51 | } 52 | 53 | public IContext Context { get; set; } 54 | 55 | public string VariableVisual { get; set; } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /TSChannel/ChannelHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using TSLab.Script.Handlers.Options; 5 | using TSLab.Utils; 6 | 7 | namespace TSLab.Script.Handlers.TSChannel 8 | { 9 | [HandlerCategory(HandlerCategories.TSChannel)] 10 | [InputsCount(1,2)] 11 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 12 | [Input(1, TemplateTypes.BOOL, Name = "On/Off")] 13 | [OutputsCount(1)] 14 | [OutputType(TemplateTypes.STRING)] 15 | public class ChannelHandler : ConstGenBase, IStreamHandler, ICustomListValues, IContextUses, INeedVariableVisual 16 | { 17 | [ApiKeyHandlerProperty(ApiKeyHandlerPropertyMode.Transmitter)] 18 | [HandlerParameter(NotOptimized = false, Editor = "TransmitterApiKeyEditor")] 19 | public string ChannelApiKey { get; set; } 20 | 21 | public IList Execute(ISecurity sec) 22 | { 23 | return ExecuteInternal(sec, true); 24 | } 25 | 26 | public IList Execute(ISecurity sec, IList enabled) 27 | { 28 | var isEnabled = enabled.LastOrDefault(); 29 | return ExecuteInternal(sec, isEnabled); 30 | } 31 | 32 | private IList ExecuteInternal(ISecurity sec, bool isEnabled) 33 | { 34 | var channelApiKey = isEnabled ? ChannelApiKey : ""; // Making empty key to skip values 35 | MakeList(sec.Bars.Count, channelApiKey); 36 | 37 | if (Context.IsOptimization) 38 | return this; 39 | 40 | if (string.IsNullOrWhiteSpace(channelApiKey)) 41 | { 42 | if (isEnabled) 43 | Context.Log($"Transmitter ApiKey'{VariableVisual}' doesn't set.", MessageType.Error); 44 | return this; 45 | } 46 | 47 | try 48 | { 49 | var service = Locator.Current.GetInstance(); 50 | service.RegisterTransmitterForUpdates(sec, channelApiKey); 51 | } 52 | catch (Exception e) 53 | { 54 | Context.Log(e.Message, MessageType.Error); 55 | } 56 | 57 | return this; 58 | } 59 | 60 | public IContext Context { get; set; } 61 | 62 | public IEnumerable GetValuesForParameter(string paramName) 63 | { 64 | return new[] { ChannelApiKey }; 65 | } 66 | 67 | public string VariableVisual { get; set; } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /TSChannel/IsReceiverOnline.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using TSLab.Script.Handlers.Options; 4 | using TSLab.Utils; 5 | 6 | namespace TSLab.Script.Handlers.TSChannel 7 | { 8 | [HandlerCategory(HandlerCategories.TSChannel)] 9 | [InputsCount(1)] 10 | [Input(0, TemplateTypes.STRING, Name = Constants.SecuritySource)] 11 | [OutputsCount(1)] 12 | [OutputType(TemplateTypes.BOOL)] 13 | [NotCacheable] 14 | public class IsReceiverOnline : ConstGenBase, IStreamHandler, IContextUses 15 | { 16 | public IList Execute(IList receiver) 17 | { 18 | if (receiver.Count == 0) 19 | return Array.Empty(); 20 | 21 | var receiverApiKey = receiver[0]; 22 | var dsName = (string)Context.LoadObject(receiverApiKey); 23 | var service = Locator.Current.GetInstance(); 24 | var v = service.IsReceiverReady(receiverApiKey, dsName); 25 | MakeList(receiver.Count, v); 26 | return this; 27 | } 28 | 29 | public IContext Context { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /TSChannel/ParameterSenderHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TSLab.Script.Handlers.Options; 3 | using TSLab.Utils; 4 | 5 | namespace TSLab.Script.Handlers.TSChannel 6 | { 7 | [HandlerCategory(HandlerCategories.TSChannel)] 8 | [InputsCount(1, 2)] 9 | [Input(0, TemplateTypes.STRING, Name = Constants.SecuritySource)] 10 | [Input(1, TemplateTypes.STRING, Name = "Prefix")] 11 | [OutputsCount(0)] 12 | public class ParameterSenderHandler : IContextUses, INeedVariableVisual, IValuesHandlerWithNumber 13 | { 14 | /// 15 | /// \~english A value to return as output of a handler 16 | /// \~russian Значение на выходе блока 17 | /// 18 | [HandlerParameter(NotOptimized = false)] 19 | public double Value { get; set; } 20 | 21 | public void Execute(string apiKey, int bar) 22 | { 23 | Execute(apiKey, "", bar); 24 | } 25 | 26 | public void Execute(string apiKey, string prefix, int bar) 27 | { 28 | if (Context.IsOptimization) 29 | return; 30 | var barsCount = Context.BarsCount; 31 | if (!Context.IsLastBarUsed) 32 | barsCount--; 33 | if (bar != barsCount - 1) 34 | return; 35 | var service = Locator.Current.GetInstance(); 36 | service.SetValue(apiKey, $"{prefix}{VariableVisual}", Value); 37 | } 38 | 39 | public IContext Context { get; set; } 40 | 41 | public string VariableVisual { get; set; } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /TSChannel/ReceiverHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Xml.Linq; 4 | using TSLab.Script.Handlers.Options; 5 | using TSLab.Utils; 6 | 7 | namespace TSLab.Script.Handlers.TSChannel 8 | { 9 | [HandlerCategory(HandlerCategories.TSChannel)] 10 | [InputsCount(1)] 11 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 12 | [OutputsCount(1)] 13 | [OutputType(TemplateTypes.STRING)] 14 | public class ReceiverHandler : ConstGenBase, IStreamHandler, IContextUses, ICustomListValues, INeedVariableVisual 15 | { 16 | [ApiKeyHandlerProperty(ApiKeyHandlerPropertyMode.Receiver)] 17 | [HandlerParameter(NotOptimized = false, IsTransparentSetValue = true, Editor = "ReceiverApiKeyEditor")] 18 | public string ReceiverApiKey { get; set; } 19 | 20 | [ApiKeyHandlerProperty(ApiKeyHandlerPropertyMode.Channel)] 21 | [HandlerParameter(NotOptimized = false, Editor = "ChannelApiKeyEditor")] 22 | public string ChannelApiKey { get; set; } 23 | 24 | public IList Execute(ISecurity sec) 25 | { 26 | var receiverApiKey = ReceiverApiKey; 27 | MakeList(sec.Bars.Count, receiverApiKey); 28 | 29 | if (Context.IsOptimization) 30 | return this; 31 | if (string.IsNullOrWhiteSpace(receiverApiKey)) 32 | { 33 | Context.Log($"Receiver ApiKey'{VariableVisual}' doesn't set.", MessageType.Error); 34 | return this; 35 | } 36 | 37 | var service = Locator.Current.GetInstance(); 38 | try 39 | { 40 | var dsName = sec.SecurityDescription.DSName; 41 | Context.StoreObject(receiverApiKey, dsName); 42 | service.RegisterReceiverForUpdates(receiverApiKey, ChannelApiKey, dsName, 43 | () => Context.Recalc("TSChannel", sec.SecurityDescription)); 44 | } 45 | catch (Exception e) 46 | { 47 | Context.Log(e.Message, MessageType.Error); 48 | //MakeList(sec.Bars.Count, receiverApiKey); 49 | } 50 | 51 | return this; 52 | } 53 | 54 | public IContext Context { get; set; } 55 | 56 | public IEnumerable GetValuesForParameter(string paramName) 57 | { 58 | if (paramName.EqualsIgnoreCase(nameof(ReceiverApiKey))) 59 | return new[] { ReceiverApiKey }; 60 | if (paramName.EqualsIgnoreCase(nameof(ChannelApiKey))) 61 | return new[] { ChannelApiKey }; 62 | return EmptyArrays.String; 63 | } 64 | 65 | public string VariableVisual { get; set; } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /TSChannel/ValueReceiverHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using TSLab.Script.Handlers.Options; 4 | using TSLab.Utils; 5 | 6 | namespace TSLab.Script.Handlers.TSChannel 7 | { 8 | [HandlerCategory(HandlerCategories.TSChannel)] 9 | [InputsCount(1, 2)] 10 | [Input(0, TemplateTypes.STRING, Name = Constants.SecuritySource)] 11 | [Input(1, TemplateTypes.STRING, Name = "Prefix")] 12 | [OutputsCount(1)] 13 | [OutputType(TemplateTypes.DOUBLE)] 14 | [NotCacheable] 15 | public class ValueReceiverHandler : ConstGenBase, IStreamHandler, INeedVariableVisual, IContextUses 16 | { 17 | [HandlerParameter(NotOptimized = false)] 18 | public double Value { get; set; } 19 | 20 | 21 | [HandlerParameter(true, "0")] 22 | public double DefaultValue { get; set; } 23 | 24 | public IList Execute(IList receiver) 25 | { 26 | return Execute(receiver, null); 27 | } 28 | 29 | public IList Execute(IList receiver, IList prefix) 30 | { 31 | if (receiver.Count == 0) 32 | return Array.Empty(); 33 | 34 | var service = Locator.Current.GetInstance(); 35 | var v = DefaultValue; 36 | 37 | try 38 | { 39 | var pfx = prefix == null ? "" : prefix[0]; 40 | var name = $"{pfx}{VariableVisual}"; 41 | v = service.GetValue(receiver[0], name, DefaultValue); 42 | } 43 | catch (Exception e) 44 | { 45 | Context.Log(e.Message, MessageType.Error); 46 | } 47 | 48 | MakeList(receiver.Count, v); 49 | Value = v; 50 | return this; 51 | } 52 | 53 | public IContext Context { get; set; } 54 | 55 | public string VariableVisual { get; set; } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /TSChannel/ValueSenderHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TSLab.Script.Handlers.Options; 3 | using TSLab.Utils; 4 | 5 | namespace TSLab.Script.Handlers.TSChannel 6 | { 7 | [HandlerCategory(HandlerCategories.TSChannel)] 8 | [InputsCount(2, 3)] 9 | [Input(0, TemplateTypes.STRING, Name = Constants.SecuritySource)] 10 | [Input(1, TemplateTypes.DOUBLE | TemplateTypes.INT | TemplateTypes.BOOL, Name = "Value")] 11 | [Input(2, TemplateTypes.STRING, Name = "Prefix")] 12 | [OutputsCount(0)] 13 | public class ValueSenderHandler : ITwoSourcesHandler, IContextUses, INeedVariableVisual, IValuesHandlerWithNumber 14 | { 15 | public void Execute(string apiKey, bool v, int bar) 16 | { 17 | Execute(apiKey, v, "", bar); 18 | } 19 | 20 | public void Execute(string apiKey, bool v, string prefix, int bar) 21 | { 22 | Execute(apiKey, Convert.ToDouble(v), prefix, bar); 23 | } 24 | 25 | public void Execute(string apiKey, double v, int bar) 26 | { 27 | Execute(apiKey, v, "", bar); 28 | } 29 | 30 | public void Execute(string apiKey, double v, string prefix, int bar) 31 | { 32 | if (Context.IsOptimization) 33 | return; 34 | 35 | var barsCount = Context.BarsCount; 36 | if (!Context.IsLastBarUsed) 37 | barsCount--; 38 | if (bar != barsCount - 1) 39 | return; 40 | var service = Locator.Current.GetInstance(); 41 | service.SetValue(apiKey, $"{prefix}{VariableVisual}", v); 42 | } 43 | 44 | public IContext Context { get; set; } 45 | 46 | public string VariableVisual { get; set; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TradeMath/BarNumber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | 6 | using TSLab.Script.Handlers.Options; 7 | 8 | namespace TSLab.Script.Handlers 9 | { 10 | // TODO: правильней назвать кубик Bar INDEX или Index of the bar 11 | [HandlerCategory(HandlerCategories.TradeMath)] 12 | [HelperName("Bar number", Language = Constants.En)] 13 | [HelperName("Номер бара", Language = Constants.Ru)] 14 | [InputsCount(1)] 15 | [Input(0, TemplateTypes.SECURITY | TemplateTypes.DOUBLE | TemplateTypes.INT | TemplateTypes.BOOL)] 16 | [OutputsCount(1)] 17 | [OutputType(TemplateTypes.DOUBLE)] 18 | [Description("Индекс элемента в списке баров или числовых значений.")] 19 | [HelperDescription("An index of an element in a list of bars or numeric values.", Constants.En)] 20 | public sealed class BarNumber : IOneSourceHandler, IDoubleReturns, IStreamHandler, ISecurityInputs, IDoubleInputs, IIntInputs, IBooleanInputs 21 | { 22 | /// 23 | /// Рудиментарная реализация интерфейса IList[double], которая для экономии памяти и повышения скорости 24 | /// обеспечивает только минимальный функционал. В качестве 'элементов' выступают индексы исходного списка баров. 25 | /// 26 | private sealed class IndexList : IList, IReadOnlyList 27 | { 28 | public IndexList(int count) 29 | { 30 | Count = count; 31 | } 32 | 33 | public IEnumerator GetEnumerator() 34 | { 35 | for (var i = 0; i < Count; i++) 36 | yield return i; 37 | } 38 | 39 | IEnumerator IEnumerable.GetEnumerator() 40 | { 41 | return GetEnumerator(); 42 | } 43 | 44 | public void Add(double item) 45 | { 46 | throw new NotSupportedException(); 47 | } 48 | 49 | public void Clear() 50 | { 51 | throw new NotSupportedException(); 52 | } 53 | 54 | public bool Contains(double item) 55 | { 56 | return IndexOf(item) >= 0; 57 | } 58 | 59 | public void CopyTo(double[] array, int arrayIndex) 60 | { 61 | throw new NotSupportedException(); 62 | } 63 | 64 | public bool Remove(double item) 65 | { 66 | throw new NotSupportedException(); 67 | } 68 | 69 | public int Count { get; } 70 | 71 | public bool IsReadOnly => true; 72 | 73 | public int IndexOf(double item) 74 | { 75 | var indexOf = (int)item; 76 | if (item != indexOf) 77 | throw new ArgumentException(nameof(item)); 78 | 79 | return indexOf >= 0 && indexOf < Count ? indexOf : -1; 80 | } 81 | 82 | public void Insert(int index, double item) 83 | { 84 | throw new NotSupportedException(); 85 | } 86 | 87 | public void RemoveAt(int index) 88 | { 89 | throw new NotSupportedException(); 90 | } 91 | 92 | public double this[int index] 93 | { 94 | get 95 | { 96 | if (index >= 0 && index < Count) 97 | return index; 98 | 99 | throw new ArgumentOutOfRangeException(nameof(index)); 100 | } 101 | set => throw new NotSupportedException(); 102 | } 103 | } 104 | 105 | public IList Execute(ISecurity security) 106 | { 107 | return new IndexList(security.Bars.Count); 108 | } 109 | 110 | public IList Execute(IList security) 111 | { 112 | return new IndexList(security.Count); 113 | } 114 | 115 | public IList Execute(IList security) 116 | { 117 | return new IndexList(security.Count); 118 | } 119 | 120 | public IList Execute(IList security) 121 | { 122 | return new IndexList(security.Count); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /TradeMath/BarsConstructorHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using TSLab.DataSource; 6 | using TSLab.Script.Handlers.Options; 7 | 8 | // ReSharper disable once CheckNamespace 9 | namespace TSLab.Script.Handlers 10 | { 11 | [HandlerCategory(HandlerCategories.TradeMath)] 12 | [HelperName("Bars Constructor", Language = Constants.En)] 13 | [HelperName("Конструктор баров", Language = Constants.Ru)] 14 | [InputsCount(5)] 15 | [Input(0, TemplateTypes.DOUBLE, Name = "Open")] 16 | [Input(1, TemplateTypes.DOUBLE, Name = "Close")] 17 | [Input(2, TemplateTypes.DOUBLE, Name = "High")] 18 | [Input(3, TemplateTypes.DOUBLE, Name = "Low")] 19 | [Input(4, TemplateTypes.DOUBLE, Name = "Volume")] 20 | [OutputsCount(1)] 21 | [OutputType(TemplateTypes.SECURITY)] 22 | [Description("Кубик преобразует 5 числовых серий на входе в синтетический инструмент с барами. Порядок входов: открытие, закрытие, максимум, минимум, объем.")] 23 | [HelperDescription("Handler converts 5 input numeric series to a synthetic security with bars. Inputs are: open, close, high, low, volume.", Constants.En)] 24 | public sealed class BarsConstructorHandler : BarsConstructorBase, IFiveSourcesHandler, ISecurityReturns, IStreamHandler, IDoubleInputs, IContextUses, INeedVariableName 25 | { 26 | public IContext Context { get; set; } 27 | public string VariableName { get; set; } 28 | 29 | public ISecurity Execute(IList openList, IList closeList, IList highList, IList lowList, IList volumeList) 30 | { 31 | if (openList == null) 32 | throw new ArgumentNullException(nameof(openList)); 33 | 34 | if (closeList == null) 35 | throw new ArgumentNullException(nameof(closeList)); 36 | 37 | if (highList == null) 38 | throw new ArgumentNullException(nameof(highList)); 39 | 40 | if (lowList == null) 41 | throw new ArgumentNullException(nameof(lowList)); 42 | 43 | if (volumeList == null) 44 | throw new ArgumentNullException(nameof(volumeList)); 45 | 46 | var security = Context.Runtime.Securities.First(); 47 | var securityBars = security.Bars; 48 | var count = Math.Min(openList.Count, Math.Min(closeList.Count, Math.Min(highList.Count, Math.Min(lowList.Count, Math.Min(volumeList.Count, securityBars.Count))))); 49 | var bars = new IDataBar[count]; 50 | 51 | for (var i = 0; i < count; i++) 52 | bars[i] = new DataBar(securityBars[i].Date, openList[i], highList[i], lowList[i], closeList[i], volumeList[i]); 53 | 54 | return new Security(bars, VariableName, security); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /TradeMath/BarsTickDataHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using TSLab.DataSource; 6 | using TSLab.Script.Handlers.Options; 7 | using TSLab.Utils; 8 | 9 | // ReSharper disable once CheckNamespace 10 | namespace TSLab.Script.Handlers 11 | { 12 | [HandlerCategory(HandlerCategories.TradeMath)] 13 | [HelperName("Bars tick data", Language = Constants.En)] 14 | [HelperName("Бары котировочных данных", Language = Constants.Ru)] 15 | [InputsCount(1)] 16 | [Input(0, TemplateTypes.SECURITY, Name = "SECURITYSource")] 17 | [OutputsCount(1)] 18 | [OutputType(TemplateTypes.SECURITY)] 19 | [Description("Предназначен для работы с кешируемыми данными из котировок. Строит бары с интервалом источника. Для работы используйте секундный интервал источника. Например, 60 секунд.")] 20 | [HelperDescription("Designed to work with cached data from quotes. Builds bars with the source interval. To work, use the second interval of the source. For example, 60 seconds.", Constants.En)] 21 | public sealed class BarsTickDataHandler : BarsConstructorBase, ISecurityReturns, IStreamHandler, ISecurityInputs, 22 | IContextUses, INeedVariableName 23 | { 24 | [HelperName("Data quotes", Constants.En)] 25 | [HelperName("Данные котировок", Constants.Ru)] 26 | [HandlerParameter(true, nameof(BarsTickDataField.BuyCount))] 27 | public BarsTickDataField Field { get; set; } 28 | public IContext Context { get; set; } 29 | public string VariableName { get; set; } 30 | 31 | public ISecurity Execute(ISecurity security) 32 | { 33 | var newBars = new IDataBar[Context.BarsCount]; 34 | for (int i = 0; i < newBars.Length; i++) 35 | { 36 | var bar = security.Bars[i]; 37 | var trades = GetData(security, i, Field).ToList(); 38 | if (trades.Count == 0) 39 | { 40 | newBars[i] = i > 0 ? newBars[i - 1] : new DataBar(bar.Date, 0, 0, 0, 0); 41 | } 42 | else 43 | { 44 | var open = trades.First(); 45 | var high = trades.Max(); 46 | var low = trades.Min(); 47 | var close = trades.Last(); 48 | newBars[i] = new DataBar(bar.Date, open, high, low, close); 49 | } 50 | } 51 | return new Security(newBars, VariableName, security); 52 | } 53 | 54 | private static IEnumerable GetData(ISecurity source, int barNum, BarsTickDataField field) 55 | { 56 | var trades = source.GetTrades(barNum); 57 | switch (field) 58 | { 59 | case BarsTickDataField.BuyCount: 60 | return trades.OfType().Select(x => x.BuyCount); 61 | case BarsTickDataField.SellCount: 62 | return trades.OfType().Select(x => x.SellCount); 63 | case BarsTickDataField.BidQty: 64 | return trades.OfType().Select(x => x.BidQty); 65 | case BarsTickDataField.AskQty: 66 | return trades.OfType().Select(x => x.AskQty); 67 | case BarsTickDataField.OpenInterest: 68 | return trades.Select(x => x.OpenInterest); 69 | } 70 | throw new NotImplementedException(field.ToString()); 71 | } 72 | } 73 | 74 | public enum BarsTickDataField 75 | { 76 | [LocalizeDescription("BarsTickDataField.BuyCount")] // Количество заявок на Покупку 77 | BuyCount, 78 | [LocalizeDescription("BarsTickDataField.SellCount")] // Количество заявок на Продажу 79 | SellCount, 80 | [LocalizeDescription("BarsTickDataField.BidQty")] // Суммарный Спрос 81 | BidQty, 82 | [LocalizeDescription("BarsTickDataField.AskQty")] // Суммарное Предложение 83 | AskQty, 84 | [LocalizeDescription("BarsTickDataField.OpenInterest")] // Открытый интерес 85 | OpenInterest, 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /TradeMath/ConstGen.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TSLab-Dev/Handlers/7bb483dce9ac034057762f73752236ff65e021f9/TradeMath/ConstGen.cs -------------------------------------------------------------------------------- /TradeMath/ControlledBoolBreaker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using TSLab.Script.Handlers.Options; 5 | using TSLab.Script.Optimization; 6 | using TSLab.Utils; 7 | 8 | namespace TSLab.Script.Handlers.TradeMath 9 | { 10 | [HandlerCategory(HandlerCategories.TradeMath)] 11 | [HelperName("Controlled Boolean Breaker", Language = Constants.En)] 12 | [HelperName("Управляемый логический разделитель", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.BOOL)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.BOOL)] 17 | public sealed class ControlledBoolBreaker : IOneSourceHandler, IBooleanReturns, IStreamHandler, IValuesHandler, IBooleanInputs, IContextUses 18 | { 19 | public IContext Context { get; set; } 20 | 21 | /// 22 | /// \~english A value to return as output of a handler 23 | /// \~russian Значение на выходе блока 24 | /// 25 | [HelperName("Value", Constants.En)] 26 | [HelperName("Значение", Constants.Ru)] 27 | [HandlerParameter] 28 | public BoolOptimProperty Value { get; set; } 29 | 30 | public IList Execute(IList source) 31 | { 32 | if (source == null) 33 | throw new ArgumentNullException(nameof(source)); 34 | 35 | if (source.Count == 0) 36 | return EmptyArrays.Bool; 37 | 38 | if (source.Last()) 39 | Value.Value = false; 40 | 41 | return new ConstList(source.Count, Value.Value); 42 | } 43 | 44 | public bool Execute(bool value, int index) 45 | { 46 | if (index != Context.BarsCount - (Context.IsLastBarUsed ? 1 : 2)) 47 | return false; 48 | 49 | if (value) 50 | Value.Value = false; 51 | 52 | return Value.Value; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /TradeMath/ControlledBoolConst.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | 6 | using TSLab.Script.Handlers.Options; 7 | using TSLab.Utils; 8 | 9 | namespace TSLab.Script.Handlers 10 | { 11 | [HandlerCategory(HandlerCategories.TradeMath)] 12 | [HelperName("Controlled Boolean Constant", Language = Constants.En)] 13 | [HelperName("Управляемая логическая константа", Language = Constants.Ru)] 14 | [InputsCount(1)] 15 | [Input(0, TemplateTypes.BOOL)] 16 | [OutputsCount(1)] 17 | [OutputType(TemplateTypes.BOOL)] 18 | [Description("Управляемая логическая константа (переключатель). При поступлении на вход значения 'Истина' данный блок выдает значение из поля 'Значение', при поступлении на вход значения 'Ложь' используется 'Значение по умолчанию'.")] 19 | [HelperDescription("Controlled boolean constant (switch). If input is TRUE the result is taken from a field 'Value', otherwise the result is taken from a field 'Default value'.", Constants.En)] 20 | public sealed class ControlledBoolConst : IOneSourceHandler, IBooleanReturns, IStreamHandler, IValuesHandler, IBooleanInputs, IContextUses 21 | { 22 | public IContext Context { get; set; } 23 | 24 | /// 25 | /// \~english A value to return as output of a handler when input is true 26 | /// \~russian Значение на выходе блока, если на вход подать 'Истина' 27 | /// 28 | [HelperName("Value", Constants.En)] 29 | [HelperName("Значение", Constants.Ru)] 30 | [Description("Значение на выходе блока, если на вход подать 'Истина'")] 31 | [HelperDescription("A value to return as output of a handler when input is true", Constants.En)] 32 | [HandlerParameter] 33 | public bool Value { get; set; } 34 | 35 | /// 36 | /// \~english A value to return as output of a handler when input is false 37 | /// \~russian Значение на выходе блока, если на вход подать 'Ложь' 38 | /// 39 | [HelperName("Default value", Constants.En)] 40 | [HelperName("Значение по умолчанию", Constants.Ru)] 41 | [Description("Значение на выходе блока, если на вход подать 'Ложь'")] 42 | [HelperDescription("A value to return as output of a handler when input is false", Constants.En)] 43 | [HandlerParameter(NotOptimized = true)] 44 | public bool DefaultValue { get; set; } 45 | 46 | public IList Execute(IList source) 47 | { 48 | if (source == null) 49 | throw new ArgumentNullException(nameof(source)); 50 | 51 | if (source.Count == 0) 52 | return EmptyArrays.Bool; 53 | 54 | var firstValue = source[0]; 55 | if (source.All(item => item == firstValue)) 56 | return new ConstList(source.Count, firstValue ? Value : DefaultValue); 57 | 58 | var result = Context?.GetArray(source.Count) ?? new bool[source.Count]; 59 | for (var i = 0; i < result.Length; i++) 60 | result[i] = source[i] ? Value : DefaultValue; 61 | 62 | return result; 63 | } 64 | 65 | public bool Execute(bool value, int index) 66 | { 67 | return value ? Value : DefaultValue; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /TradeMath/ExtremePos.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using TSLab.Script.Handlers.Options; 4 | using TSLab.Script.Helpers; 5 | 6 | namespace TSLab.Script.Handlers 7 | { 8 | /// 9 | /// Базовый класс для группы кубиков, которые вычисляют сколько прошло баров с предыдущего экстремума 10 | /// 11 | [HandlerCategory(HandlerCategories.TradeMath)] 12 | [InputsCount(1)] 13 | [Input(0, TemplateTypes.DOUBLE)] 14 | [OutputsCount(1)] 15 | [OutputType(TemplateTypes.DOUBLE)] 16 | public abstract class ExtremePos : IDouble2DoubleHandler, IContextUses 17 | { 18 | public IContext Context { get; set; } 19 | 20 | /// 21 | /// \~english Indicator period (processing window) 22 | /// \~russian Период индикатора (окно расчетов) 23 | /// 24 | [HelperName("Period", Constants.En)] 25 | [HelperName("Период", Constants.Ru)] 26 | [Description("Период индикатора (окно расчетов)")] 27 | [HelperDescription("Indicator period (processing window)", Constants.En)] 28 | [HandlerParameter(true, "20", Min = "10", Max = "100", Step = "5", EditorMin = "1")] 29 | public int Period { get; set; } 30 | 31 | public IList Execute(IList source) 32 | { 33 | var extremeValues = GetExtremeValues(source); 34 | var result = Context?.GetArray(source.Count) ?? new double[source.Count]; 35 | 36 | for (var i = 1; i < result.Length; i++) 37 | { 38 | var k = 0; 39 | while (i - k >= 0 && extremeValues[i] != source[i - k]) 40 | k++; 41 | 42 | result[i] = k; 43 | } 44 | return result; 45 | } 46 | 47 | protected abstract IList GetExtremeValues(IList source); 48 | } 49 | 50 | //[HandlerCategory(HandlerCategories.TradeMath)] 51 | // Категория и описание входов/выходов идет через базовый класс. 52 | [HelperName("Bars since last high", Language = Constants.En)] 53 | [HelperName("Баров с последнего максимума", Language = Constants.Ru)] 54 | [Description("Количество баров, прошедшее с момента последнего обновления максимума.")] 55 | [HelperDescription("The number of bars since the latest high.", Constants.En)] 56 | public sealed class HighestPos : ExtremePos 57 | { 58 | protected override IList GetExtremeValues(IList source) 59 | { 60 | return Series.Highest(source.AsReadOnly(), Period, Context); 61 | } 62 | } 63 | 64 | //[HandlerCategory(HandlerCategories.TradeMath)] 65 | // Категория и описание входов/выходов идет через базовый класс. 66 | [HelperName("Bars since last low", Language = Constants.En)] 67 | [HelperName("Баров с последнего минимума", Language = Constants.Ru)] 68 | [Description("Количество баров, прошедшее с момента последнего обновления минимума.")] 69 | [HelperDescription("The number of bars since the latest low.", Constants.En)] 70 | public sealed class LowestPos : ExtremePos 71 | { 72 | protected override IList GetExtremeValues(IList source) 73 | { 74 | return Series.Lowest(source.AsReadOnly(), Period, Context); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /TradeMath/FinInfoHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | 5 | using TSLab.DataSource; 6 | using TSLab.Script.Handlers.Options; 7 | using TSLab.Utils; 8 | 9 | namespace TSLab.Script.Handlers 10 | { 11 | /// 12 | /// Базовый класс для группы кубиков, которые используют FinInfo 13 | /// 14 | [HandlerCategory(HandlerCategories.TradeMath)] 15 | [InputsCount(1)] 16 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 17 | [OutputsCount(1)] 18 | [OutputType(TemplateTypes.DOUBLE)] 19 | public abstract class FinInfoHandler : IBar2DoubleHandler//, IContextUses 20 | { 21 | //public IContext Context { get; set; } 22 | 23 | public IList Execute(ISecurity source) 24 | { 25 | return new ConstList(source.Bars.Count, GetValue(source.FinInfo) ?? 0); 26 | } 27 | 28 | protected abstract double? GetValue(FinInfo finInfo); 29 | } 30 | 31 | // Гарантийные обязательства покупателя 32 | public sealed class BuyDeposit : FinInfoHandler 33 | { 34 | protected override double? GetValue(FinInfo finInfo) 35 | { 36 | return finInfo.BuyDeposit; 37 | } 38 | } 39 | 40 | // Гарантийные обязательства продавца 41 | public sealed class SellDeposit : FinInfoHandler 42 | { 43 | protected override double? GetValue(FinInfo finInfo) 44 | { 45 | return finInfo.SellDeposit; 46 | } 47 | } 48 | 49 | // Наибольшая цена спроса в течение торговой сессии 50 | public sealed class HighBid : FinInfoHandler 51 | { 52 | protected override double? GetValue(FinInfo finInfo) 53 | { 54 | return finInfo.HighBid; 55 | } 56 | } 57 | 58 | // Наименьшая цена предложения в течение торговой сессии 59 | public sealed class LowOffer : FinInfoHandler 60 | { 61 | protected override double? GetValue(FinInfo finInfo) 62 | { 63 | return finInfo.LowOffer; 64 | } 65 | } 66 | 67 | // Нижний лимит цены 68 | public sealed class PriceMin : FinInfoHandler 69 | { 70 | protected override double? GetValue(FinInfo finInfo) 71 | { 72 | return finInfo.PriceMin; 73 | } 74 | } 75 | 76 | // Верхний лимит цены 77 | public sealed class PriceMax : FinInfoHandler 78 | { 79 | protected override double? GetValue(FinInfo finInfo) 80 | { 81 | return finInfo.PriceMax; 82 | } 83 | } 84 | 85 | // Категория и описание входов/выходов идет через базовый класс. 86 | [HelperName("Price step", Language = Constants.En)] 87 | [HelperName("Шаг цены", Language = Constants.Ru)] 88 | [Description("Шаг цены инструмента. Эта же величина показывается в таблице 'Котировки'.")] 89 | [HelperDescription("Price step of a security. This value is shown also in 'Quotes' table.", Constants.En)] 90 | public sealed class Tick : FinInfoHandler 91 | { 92 | protected override double? GetValue(FinInfo finInfo) 93 | { 94 | if (finInfo == null || finInfo.Security == null) 95 | return 1; 96 | 97 | var lastPrice = finInfo.LastPrice ?? 0.0; 98 | var tick = finInfo.Security.GetTick(lastPrice); 99 | if (!DoubleUtil.IsPositive(tick)) 100 | tick = Math.Pow(10, -finInfo.Security.Decimals); 101 | 102 | return tick; 103 | } 104 | } 105 | 106 | // Категория и описание входов/выходов идет через базовый класс. 107 | [HelperName("Lot step", Language = Constants.En)] 108 | [HelperName("Шаг лота", Language = Constants.Ru)] 109 | [Description("Шаг лота инструмента. Эта же величина показывается в таблице 'Котировки'.")] 110 | [HelperDescription("Lot step of a security. This value is shown also in 'Quotes' table.", Constants.En)] 111 | public sealed class LotTick : FinInfoHandler 112 | { 113 | protected override double? GetValue(FinInfo finInfo) 114 | { 115 | return finInfo?.Security?.LotTick; 116 | } 117 | } 118 | 119 | [HelperName("Lot size", Language = Constants.En)] 120 | [HelperName("Размер лота", Language = Constants.Ru)] 121 | [Description("Размер лота инструмента. Блок возвращает количество акций в одном лоте. Эта же величина показывается в таблице 'Котировки'.")] 122 | [HelperDescription("Lot size of a security. The block returns the number of shares in one lot. This value is shown also in 'Quotes' table.", Constants.En)] 123 | public sealed class LotSize : FinInfoHandler 124 | { 125 | protected override double? GetValue(FinInfo finInfo) 126 | { 127 | return finInfo?.Security?.LotSize; 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /TradeMath/Ln.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using TSLab.Script.Handlers.Options; 5 | 6 | namespace TSLab.Script.Handlers 7 | { 8 | [HandlerCategory(HandlerCategories.TradeMath)] 9 | [HelperName("Ln", Language = Constants.En)] 10 | [HelperName("Ln", Language = Constants.Ru)] 11 | [InputsCount(1)] 12 | [Input(0, TemplateTypes.DOUBLE)] 13 | [OutputsCount(1)] 14 | [OutputType(TemplateTypes.DOUBLE)] 15 | [Description("Натуральный логарифм (Ln) для серии значений.")] 16 | [HelperDescription("A natural logarithm (Ln) for a values series.", Constants.En)] 17 | public sealed class Ln : IDouble2DoubleHandler, IValuesHandlerWithNumber 18 | { 19 | private double m_mult = 1, m_add = 0; 20 | 21 | /// 22 | /// \~english A result of logarithm may be multiplied by this coefficient ( Mult*LN(x) + Add ) 23 | /// \~russian Результат логарифмирования можно сразу умножить на этот коэффициент ( Mult*LN(x) + Add ) 24 | /// 25 | [HelperName("Multiply", Constants.En)] 26 | [HelperName("Множитель", Constants.Ru)] 27 | [Description("Результат логарифмирования можно сразу умножить на этот коэффициент ( Mult*LN(x) + Add )")] 28 | [HelperDescription("A result of logarithm may be multiplied by this coefficient ( Mult*LN(x) + Add )", Constants.En)] 29 | [HandlerParameter(true, Default = "1")] 30 | public double Mult 31 | { 32 | get { return m_mult; } 33 | set { m_mult = value; } 34 | } 35 | 36 | /// 37 | /// \~english A result of logarithm (after multiplication) may be shifted by this value ( Mult*LN(x) + Add ) 38 | /// \~russian Результат логарифмирования (после домножения) можно увеличить на этот сдвиг ( Mult*LN(x) + Add ) 39 | /// 40 | [HelperName("Add", Constants.En)] 41 | [HelperName("Прибавить", Constants.Ru)] 42 | [Description("Результат логарифмирования (после домножения) можно увеличить на этот сдвиг ( Mult*LN(x) + Add )")] 43 | [HelperDescription("A result of logarithm (after multiplication) may be shifted by this value ( Mult*LN(x) + Add )", Constants.En)] 44 | [HandlerParameter(true, Default = "0")] 45 | public double Add 46 | { 47 | get { return m_add; } 48 | set { m_add = value; } 49 | } 50 | 51 | /// 52 | /// Обработчик для интерфейса IStreamHandler 53 | /// 54 | public IList Execute(IList bars) 55 | { 56 | IList list = new List(bars.Count); 57 | for (int j = 0; j < bars.Count; j++) 58 | { 59 | double res = m_mult * Math.Log(bars[j]) + m_add; 60 | list.Add(res); 61 | } 62 | return list; 63 | } 64 | 65 | /// 66 | /// Обработчик для интерфейса IValuesHandlerWithNumber 67 | /// 68 | public double Execute(double barVal, int barNum) 69 | { 70 | double res = m_mult * Math.Log(barVal) + m_add; 71 | return res; 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /TradeMath/Multiply.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using TSLab.Script.Handlers.Options; 5 | 6 | namespace TSLab.Script.Handlers 7 | { 8 | [HandlerCategory(HandlerCategories.TradeMath)] 9 | //[HandlerName("Multiply by Coef", Language = "en-US")] 10 | //[HandlerName("Умножить на число", Language = "ru-RU")] 11 | [HelperName("Multiply by", Language = Constants.En)] 12 | [HelperName("Умножить на", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.DOUBLE)] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Умножение каждого элемента входной серии на заданный коэффициент.")] 18 | [HelperDescription("Multiplies each item of input by a constant factor.", Constants.En)] 19 | public sealed class Multiply : IDouble2DoubleHandler, IValuesHandlerWithNumber, IContextUses 20 | { 21 | /// 22 | /// \~english Every item of input is multiplied by this coefficient ( Mult*x ) 23 | /// \~russian Каждый элемент входной серии умножается на указанный коэффициент ( Mult*x ) 24 | /// 25 | [HelperName("Multiply", Constants.En)] 26 | [HelperName("Множитель", Constants.Ru)] 27 | [Description("Каждый элемент входной серии умножается на указанный коэффициент ( Mult*x )")] 28 | [HelperDescription("Every item of input is multiplied by this coefficient ( Mult*x )", Constants.En)] 29 | [HandlerParameter(true, "2", Min = "0.5", Max = "5", Step = "0.5")] 30 | public double Coef 31 | { 32 | get; 33 | set; 34 | } 35 | 36 | /// 37 | /// Обработчик для интерфейса IStreamHandler 38 | /// 39 | public IList Execute(IList bars) 40 | { 41 | var count = bars.Count; 42 | var res = Context?.GetArray(count) ?? new double[count]; 43 | for (var index = 0; index < bars.Count; index++) 44 | { 45 | res[index] = bars[index] * Coef; 46 | } 47 | 48 | return res; 49 | } 50 | 51 | /// 52 | /// Обработчик для интерфейса IValuesHandlerWithNumber 53 | /// 54 | public double Execute(double barVal, int barNum) 55 | { 56 | var res = barVal * Coef; 57 | return res; 58 | } 59 | 60 | public IContext Context { get; set; } 61 | } 62 | } -------------------------------------------------------------------------------- /TradeMath/OrderBookPrice.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TSLab.Script.Handlers.Options; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | 7 | [HandlerCategory(HandlerCategories.TradeMath)] 8 | [HelperName("OrderBookPrice", Language = Constants.En)] 9 | [HelperName("OrderBookPrice", Language = Constants.Ru)] 10 | [InputsCount(1)] 11 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 12 | [OutputsCount(1)] 13 | [OutputType(TemplateTypes.DOUBLE)] 14 | public sealed class OrderBookPrice : IBar2ValueDoubleHandler 15 | { 16 | [HandlerParameter] 17 | public bool Buy { get; set; } 18 | [HandlerParameter(Min = "0", Default = "0")] 19 | public int Index { get; set; } 20 | 21 | public double Execute(ISecurity sec, int barNum) 22 | { 23 | var qds = Buy ? sec.GetBuyQueue(0) : sec.GetSellQueue(0); 24 | if (qds?.Count > 0 && Index >= 0 && qds.Count > Index) 25 | { 26 | var qd = qds[Index]; 27 | return qd?.Price ?? 0.0; 28 | } 29 | 30 | return 0d; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TradeMath/OrderBookQty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TSLab.Script.Handlers.Options; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | [HandlerCategory(HandlerCategories.TradeMath)] 7 | [HelperName("OrderBookQuantity", Language = Constants.En)] 8 | [HelperName("OrderBookQuantity", Language = Constants.Ru)] 9 | [InputsCount(1)] 10 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 11 | [OutputsCount(1)] 12 | [OutputType(TemplateTypes.DOUBLE)] 13 | public sealed class OrderBookQty : IBar2ValueDoubleHandler 14 | { 15 | [HandlerParameter] 16 | public bool Buy { get; set; } 17 | [HandlerParameter(Min = "0", Default= "0")] 18 | public int Index { get; set; } 19 | 20 | public double Execute(ISecurity sec, int barNum) 21 | { 22 | var qds = Buy ? sec.GetBuyQueue(0) : sec.GetSellQueue(0); 23 | if (qds?.Count > 0 && Index >= 0 && qds.Count > Index) 24 | { 25 | var qd = qds[Index]; 26 | return qd?.Quantity ?? 0.0; 27 | } 28 | 29 | return 0d; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TradeMath/OrderBookTotal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TSLab.Script.Handlers.Options; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | [HandlerCategory(HandlerCategories.TradeMath)] 7 | [HelperName("OrderBookTotal", Language = Constants.En)] 8 | [HelperName("OrderBookTotal", Language = Constants.Ru)] 9 | [InputsCount(1)] 10 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 11 | [OutputsCount(1)] 12 | [OutputType(TemplateTypes.DOUBLE)] 13 | public class OrderBookTotal : IBar2ValueDoubleHandler 14 | { 15 | [HandlerParameter] 16 | public bool Buy { get; set; } 17 | [HandlerParameter(Min = "0", Default = "0")] 18 | public int NumberRows { get; set; } 19 | 20 | public double Execute(ISecurity sec, int barNum) 21 | { 22 | if (NumberRows > 0) 23 | { 24 | var qds = Buy ? sec.GetBuyQueue(0) : sec.GetSellQueue(0); 25 | if (qds?.Count > 0) 26 | { 27 | var cnt = qds.Count > NumberRows ? NumberRows : qds.Count; 28 | double total = 0d; 29 | for (int i = 0; i < cnt; i++) 30 | { 31 | var qd = qds[i]; 32 | total += qd.Quantity; 33 | } 34 | return total; 35 | } 36 | } 37 | 38 | return 0d; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /TradeMath/RandomHandler.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TSLab-Dev/Handlers/7bb483dce9ac034057762f73752236ff65e021f9/TradeMath/RandomHandler.cs -------------------------------------------------------------------------------- /TradeMath/ResettableControlledBoolConst.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | 6 | using TSLab.Script.Handlers.Options; 7 | using TSLab.Script.Optimization; 8 | using TSLab.Utils; 9 | 10 | namespace TSLab.Script.Handlers 11 | { 12 | [HandlerCategory(HandlerCategories.TradeMath)] 13 | [HelperName("Resettable Controlled Boolean Constant", Language = Constants.En)] 14 | [HelperName("Сбрасываемая управляемая логическая константа", Language = Constants.Ru)] 15 | [InputsCount(2)] 16 | [Input(0, TemplateTypes.BOOL)] 17 | [Input(1, TemplateTypes.BOOL)] 18 | [OutputsCount(1)] 19 | [OutputType(TemplateTypes.BOOL)] 20 | [Description("Сбрасываемая управляемая логическая константа (переключатель). " + 21 | "При поступлении на вход значения 'Истина' данный блок выдает значение из поля 'Значение', при поступлении на вход значения 'Ложь' используется 'Значение по умолчанию'. " + 22 | "Второй вход определяет чему равно 'Значение'. Если в нем больше истин, то 'Значение' становится равно 'Значению по умолчанию'.")] 23 | [HelperDescription("Resettable controlled boolean constant (switch). " + 24 | "If input is TRUE the result is taken from a field 'Value', otherwise the result is taken from a field 'Default value'. " + 25 | "Second input determines 'Value'. If it contains more TRUE, then 'Value' is set to 'Default value'.", Constants.En)] 26 | public sealed class ResettableControlledBoolConst : ITwoSourcesHandler, IBooleanReturns, IStreamHandler, IValuesHandlerWithNumber, IBooleanInputs, IContextUses 27 | { 28 | public IContext Context { get; set; } 29 | 30 | /// 31 | /// \~english A value to return as output of a handler when input is true 32 | /// \~russian Значение на выходе блока, если на вход подать 'Истина' 33 | /// 34 | [HelperName("Value", Constants.En)] 35 | [HelperName("Значение", Constants.Ru)] 36 | [Description("Значение на выходе блока, если на вход подать 'Истина'")] 37 | [HelperDescription("A value to return as output of a handler when input is true", Constants.En)] 38 | [HandlerParameter] 39 | public BoolOptimProperty Value { get; set; } 40 | 41 | /// 42 | /// \~english A value to return as output of a handler when input is false 43 | /// \~russian Значение на выходе блока, если на вход подать 'Ложь' 44 | /// 45 | [HelperName("Default value", Constants.En)] 46 | [HelperName("Значение по умолчанию", Constants.Ru)] 47 | [Description("Значение на выходе блока, если на вход подать 'Ложь'")] 48 | [HelperDescription("A value to return as output of a handler when input is false", Constants.En)] 49 | [HandlerParameter(NotOptimized = true)] 50 | public bool DefaultValue { get; set; } 51 | 52 | public IList Execute(IList source, IList resetValues) 53 | { 54 | if (source == null) 55 | throw new ArgumentNullException(nameof(source)); 56 | 57 | if (resetValues == null) 58 | throw new ArgumentNullException(nameof(resetValues)); 59 | 60 | var count = Math.Min(source.Count, resetValues.Count); 61 | if (count == 0) 62 | return EmptyArrays.Bool; 63 | 64 | if (resetValues[count - 1]) 65 | Value.Value = DefaultValue; 66 | 67 | var firstValue = source[0]; 68 | if (source.Take(count).All(item => item == firstValue)) 69 | return new ConstList(count, firstValue ? Value : DefaultValue); 70 | 71 | var result = Context?.GetArray(count) ?? new bool[count]; 72 | for (var i = 0; i < result.Length; i++) 73 | result[i] = source[i] ? Value : DefaultValue; 74 | 75 | return result; 76 | } 77 | 78 | public bool Execute(bool source, bool resetValue, int number) 79 | { 80 | if (resetValue && number == Context.BarsCount - (Context.IsLastBarUsed ? 1 : 2)) 81 | Value.Value = DefaultValue; 82 | 83 | var result = source ? Value : DefaultValue; 84 | return result; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /TradeMath/ResultForOptimization.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | [HandlerCategory(HandlerCategories.TradeMath)] 7 | [InputsCount(1)] 8 | [Input(0, TemplateTypes.DOUBLE)] 9 | [OutputsCount(0)] 10 | public class ResultForOptimization : IOneSourceHandler, IValuesHandler, IStreamHandler, IDoubleInputs, IDoubleReturns, 11 | IContextUses, INeedVariableVisual 12 | { 13 | public IContext Context { set; get; } 14 | public string VariableVisual { get; set; } 15 | 16 | public IList Execute(IList values) 17 | { 18 | var count = values.Count; 19 | 20 | if (count < 1) 21 | return new double[0]; 22 | 23 | Context.ScriptResults[VariableVisual] = values.Last(); 24 | return values; 25 | } 26 | 27 | public double Execute(double value, int barNum) 28 | { 29 | Context.ScriptResults[VariableVisual] = value; 30 | return value; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TradeMath/TextHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using TSLab.Script.Handlers.Options; 5 | 6 | namespace TSLab.Script.Handlers 7 | { 8 | [HandlerCategory(HandlerCategories.TradeMath)] 9 | [HelperName("Text", Language = Constants.En)] 10 | [HelperName("Текст", Language = Constants.Ru)] 11 | [InputsCount(0)] 12 | [Description("Блок без входов. Содержит редактируемый строковый параметр, который будет возвращаться из блока в качестве результата его работы.")] 13 | [HelperDescription("This block has no entries. It has an editable text parameter which returns as a result of its work.", Constants.En)] 14 | public sealed class TextHandler : ConstGenBase, IStreamHandler, IStringReturns, ICustomListValues, IContextUses 15 | { 16 | public IContext Context { get; set; } 17 | 18 | /// 19 | /// \~english Text (string) 20 | /// \~russian Текст (строка) 21 | /// 22 | [HelperName("Text", Constants.En)] 23 | [HelperName("Текст", Constants.Ru)] 24 | [Description("Текст (строка)")] 25 | [HelperDescription("Text (string)", Constants.En)] 26 | [HandlerParameter(Default = "*")] 27 | public string Text { get; set; } 28 | 29 | public IList Execute() 30 | { 31 | MakeList(Context.BarsCount, Text); 32 | return this; 33 | } 34 | 35 | public IEnumerable GetValuesForParameter(string paramName) 36 | { 37 | return new[] { Text }; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TradeMath/ValueSupportedIndicator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | [Obsolete] 7 | [InputsCount(1)] 8 | [Input(0, TemplateTypes.DOUBLE, Name = "ItemConnector.Src")] 9 | public abstract class ValueSupportedIndicator : IValuesHandlerWithNumber, IDoubleReturns, IContextUses 10 | { 11 | private double[] m_result, m_source; 12 | 13 | public double Execute(double source, int i) 14 | { 15 | if (i < 0 || i >= Context.BarsCount) 16 | throw new ArgumentOutOfRangeException(nameof(i)); 17 | 18 | if (m_result == null) 19 | { 20 | m_result = Context.GetArray(Context.BarsCount); 21 | m_source = Context.GetArray(Context.BarsCount); 22 | } 23 | m_source[i] = source; 24 | return Execute(m_source, m_result, i); 25 | } 26 | 27 | protected abstract double Execute(IList source, IList result, int num); 28 | 29 | public IContext Context { get; set; } 30 | } 31 | 32 | [Obsolete] 33 | public abstract class ValueSupportedIndicatorWithPeriod : ValueSupportedIndicator 34 | { 35 | private int m_period = 1; 36 | 37 | [HandlerParameter(true, "20", Min = "10", Max = "100", Step = "5", EditorMin = "1")] 38 | public int Period 39 | { 40 | get { return m_period; } 41 | set { m_period = Math.Max(value, 1); } 42 | } 43 | } 44 | 45 | [InputsCount(2)] 46 | [Input(0, TemplateTypes.DOUBLE)] 47 | [Input(1, TemplateTypes.DOUBLE)] 48 | public abstract class ValueSupportedComparer : IValuesHandlerWithNumber, IBooleanReturns, IContextUses 49 | { 50 | private bool[] m_data; 51 | private double[] m_source1, m_source2; 52 | 53 | public bool Execute(double source1, double source2, int i) 54 | { 55 | if (m_data == null) 56 | { 57 | m_data = Context.GetArray(Context.BarsCount); 58 | m_source1 = Context.GetArray(Context.BarsCount); 59 | m_source2 = Context.GetArray(Context.BarsCount); 60 | } 61 | m_source1[i] = source1; 62 | m_source2[i] = source2; 63 | return Execute(m_source1, m_source2, m_data, i); 64 | } 65 | 66 | protected abstract bool Execute(IList source1, IList source2, IList data, int num); 67 | 68 | public IContext Context { get; set; } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /TradeMath/WeightedAveragePrice.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | using TSLab.DataSource; 5 | using TSLab.Script.Handlers.Options; 6 | using TSLab.Utils; 7 | 8 | namespace TSLab.Script.Handlers 9 | { 10 | [HandlerCategory(HandlerCategories.TradeMath)] 11 | [HelperName("Weighted average bar price", Language = Constants.En)] 12 | [HelperName("Средневзвешенная цена бара", Language = Constants.Ru)] 13 | [InputsCount(1)] 14 | [Input(0, TemplateTypes.SECURITY, Name = "SECURITYSource")] 15 | [OutputsCount(1)] 16 | [OutputType(TemplateTypes.DOUBLE)] 17 | [Description("Блок считает средневзвешенную цену бара, основываясь на сделках по инструменту. " + 18 | "Для правильной работы используйте секундный график. 1 мин = 60 сек.")] 19 | [HelperDescription("The block contains the weighted average price of a bar, about on trades on the instrument. " + 20 | "For correct work, use the second chart. 1 min = 60 sec.", Constants.En)] 21 | public class WeightedAveragePrice : IStreamHandler, IContextUses 22 | { 23 | [HelperName("Direction trades", Constants.En)] 24 | [HelperName("Направление сделок", Constants.Ru)] 25 | [HandlerParameter(true, nameof(TradeDirection2.All))] 26 | public TradeDirection2 Direction { get; set; } 27 | 28 | public IContext Context { get; set; } 29 | 30 | public IList Execute(ISecurity source) 31 | { 32 | var res = Context.GetArray(Context.BarsCount); 33 | for (int i = 0; i < res.Length; i++) 34 | { 35 | var trades = GetTrades(source, i, Direction).ToList(); 36 | var value = trades.Sum(x => x.Quantity * x.Price) / trades.Sum(x => x.Quantity); 37 | res[i] = DoubleUtil.IsNumber(value) ? value : i > 0 ? res[i - 1] : 0; 38 | } 39 | return res; 40 | } 41 | 42 | private static IEnumerable GetTrades(ISecurity source, int barNum, TradeDirection2 direction) 43 | { 44 | var tradesAll = source.GetTrades(barNum); 45 | switch (direction) 46 | { 47 | case TradeDirection2.Buys: 48 | return tradesAll.Where(x => x.Direction == TradeDirection.Buy); 49 | case TradeDirection2.Sells: 50 | return tradesAll.Where(x => x.Direction == TradeDirection.Sell); 51 | default: 52 | return tradesAll; 53 | } 54 | } 55 | } 56 | 57 | public enum TradeDirection2 58 | { 59 | [LocalizeDescription("TradeDirection2.All")] // Все 60 | All, 61 | [LocalizeDescription("TradeDirection2.Buys")] // Покупки 62 | Buys, 63 | [LocalizeDescription("TradeDirection2.Sells")] // Продажи 64 | Sells, 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ValueUpdaterExecutionOrder.cs: -------------------------------------------------------------------------------- 1 | using TSLab.Utils; 2 | 3 | namespace TSLab.Script.Handlers 4 | { 5 | public enum ValueUpdaterExecutionOrder 6 | { 7 | [LocalizeDescription("ValueUpdaterExecutionOrder.Common")] 8 | Common, 9 | [LocalizeDescription("ValueUpdaterExecutionOrder.AtTheEnd")] 10 | AtTheEnd, 11 | [LocalizeDescription("ValueUpdaterExecutionOrder.AfterExit")] 12 | AfterExit, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /VolumeAnalysis/BuysHandler.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using TSLab.Script.Handlers.Options; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | [HandlerCategory(HandlerCategories.VolumeAnalysis)] 7 | [HelperName("Buys", Language = Constants.En)] 8 | [HelperName("Покупки", Language = Constants.Ru)] 9 | [InputsCount(1)] 10 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 11 | [OutputsCount(1)] 12 | [OutputType(TemplateTypes.DOUBLE)] 13 | [Description("Показывает характеристики (количество или суммарный объем) сделок на покупку")] 14 | [HelperDescription("A handler calculates statistics (amount or total volume) of a long trades", Constants.En)] 15 | public sealed class BuysHandler : BuysSellsHandler 16 | { 17 | protected override double GetValue(ICachedTradeHistogram histogram) 18 | { 19 | return histogram.AskQuantity; 20 | } 21 | 22 | protected override int GetCount(ICachedTradeHistogram histogram) 23 | { 24 | return histogram.AskTradesCount; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /VolumeAnalysis/BuysMinusSellsHandler.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using TSLab.Script.Handlers.Options; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | [HandlerCategory(HandlerCategories.VolumeAnalysis)] 7 | [HelperName("Buys Minus Sells", Language = Constants.En)] 8 | [HelperName("Покупки минус продажи", Language = Constants.Ru)] 9 | [InputsCount(1)] 10 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 11 | [OutputsCount(1)] 12 | [OutputType(TemplateTypes.DOUBLE)] 13 | [Description("Показывает разницу характеристик (количество или суммарный объем) сделок на покупку и на продажу")] 14 | [HelperDescription("A handler calculates statistics difference (amount or total volume) of a long and short trades", Constants.En)] 15 | public sealed class BuysMinusSellsHandler : BuysSellsHandler 16 | { 17 | protected override double GetValue(ICachedTradeHistogram histogram) 18 | { 19 | return histogram.DeltaAskBidQuantity; 20 | } 21 | 22 | protected override int GetCount(ICachedTradeHistogram histogram) 23 | { 24 | return histogram.AskTradesCount - histogram.BidTradesCount; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /VolumeAnalysis/BuysSellsHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using TSLab.Script.Handlers.Options; 6 | using TSLab.Utils; 7 | 8 | namespace TSLab.Script.Handlers 9 | { 10 | //[HandlerCategory(HandlerCategories.VolumeAnalysis)] 11 | // Не стоит навешивать на абстрактные классы атрибуты категорий и описания входов/выходов. Это снижает гибкость управления в перспективе. 12 | public abstract class BuysSellsHandler : IBuysSellsHandler 13 | { 14 | public IContext Context { get; set; } 15 | 16 | /// 17 | /// \~english Market volume quantity units (shares, lots, trades count) 18 | /// \~russian Режим отображения рыночной статистики (объем, лоты, количество сделок) 19 | /// 20 | [HelperName("Quantity units", Constants.En)] 21 | [HelperName("Единицы объема", Constants.Ru)] 22 | [Description("Режим отображения рыночной статистики (объем, лоты, количество сделок)")] 23 | [HelperDescription("Market volume quantity units (shares, lots, trades count)", Constants.En)] 24 | [HandlerParameter(true, nameof(QuantityMode.Quantity))] 25 | public QuantityMode QuantityMode { get; set; } 26 | 27 | public IList Execute(ISecurity security) 28 | { 29 | if (security == null) 30 | throw new ArgumentNullException(nameof(security)); 31 | 32 | var quantityMode = QuantityMode; 33 | if (quantityMode != QuantityMode.Quantity && quantityMode != QuantityMode.QuantityInLots && quantityMode != QuantityMode.TradesCount) 34 | throw new InvalidEnumArgumentException(nameof(QuantityMode), (int)quantityMode, quantityMode.GetType()); 35 | 36 | var compressedBars = security.Bars; 37 | var compressedBarsCount = compressedBars.Count; 38 | 39 | if (compressedBarsCount == 0) 40 | return EmptyArrays.Double; 41 | 42 | var decompressedSecurity = Context.Runtime.Securities.First( 43 | item => item.SecurityDescription.Id == security.SecurityDescription.Id 44 | && item.SecurityDescription.DSName == security.SecurityDescription.DSName); 45 | var decompressedBars = decompressedSecurity.Bars; 46 | var decompressedBarsCount = decompressedBars.Count; 47 | var decompressedIndex = 0; 48 | var getValueFunc = GetValueFunc(decompressedSecurity); 49 | double[] results; 50 | 51 | if (ReferenceEquals(decompressedSecurity, security)) 52 | { 53 | results = Context.GetArray(decompressedBarsCount); 54 | while (decompressedIndex < decompressedBarsCount) 55 | results[decompressedIndex] = getValueFunc(decompressedIndex++); 56 | } 57 | else 58 | { 59 | results = Context.GetArray(compressedBarsCount); 60 | var lastCompressedIndex = compressedBarsCount - 1; 61 | double compressedResult; 62 | 63 | for (var compressedIndex = 0; compressedIndex < lastCompressedIndex; compressedIndex++) 64 | { 65 | var nextCompressedDate = compressedBars[compressedIndex + 1].Date; 66 | compressedResult = 0; 67 | 68 | while (decompressedIndex < decompressedBarsCount && decompressedBars[decompressedIndex].Date < nextCompressedDate) 69 | compressedResult += getValueFunc(decompressedIndex++); 70 | 71 | results[compressedIndex] = compressedResult; 72 | } 73 | compressedResult = 0; 74 | while (decompressedIndex < decompressedBarsCount) 75 | compressedResult += getValueFunc(decompressedIndex++); 76 | 77 | results[lastCompressedIndex] = compressedResult; 78 | } 79 | return results; 80 | } 81 | 82 | private Func GetValueFunc(ISecurity security) 83 | { 84 | var tradeHistogramsCache = TradeHistogramsCaches.Instance.GetTradeHistogramsCache(Context, security, 0); 85 | var lotSize = security.LotSize; 86 | 87 | switch (QuantityMode) 88 | { 89 | case QuantityMode.Quantity: 90 | return index => GetValue(tradeHistogramsCache.GetHistogram(index)); 91 | case QuantityMode.QuantityInLots: 92 | return index => GetValue(tradeHistogramsCache.GetHistogram(index)) / lotSize; 93 | default: 94 | return index => GetCount(tradeHistogramsCache.GetHistogram(index)); 95 | } 96 | } 97 | 98 | protected abstract double GetValue(ICachedTradeHistogram histogram); 99 | 100 | protected abstract int GetCount(ICachedTradeHistogram histogram); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /VolumeAnalysis/SellsHandler.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using TSLab.Script.Handlers.Options; 3 | 4 | namespace TSLab.Script.Handlers 5 | { 6 | [HandlerCategory(HandlerCategories.VolumeAnalysis)] 7 | [HelperName("Sells", Language = Constants.En)] 8 | [HelperName("Продажи", Language = Constants.Ru)] 9 | [InputsCount(1)] 10 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 11 | [OutputsCount(1)] 12 | [OutputType(TemplateTypes.DOUBLE)] 13 | [Description("Показывает характеристики (количество или суммарный объем) сделок на продажу")] 14 | [HelperDescription("A handler calculates statistics (amount or total volume) of a short trades", Constants.En)] 15 | public sealed class SellsHandler : BuysSellsHandler 16 | { 17 | protected override double GetValue(ICachedTradeHistogram histogram) 18 | { 19 | return histogram.BidQuantity; 20 | } 21 | 22 | protected override int GetCount(ICachedTradeHistogram histogram) 23 | { 24 | return histogram.BidTradesCount; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /VolumeAnalysis/VolumeForPeriodHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | using TSLab.Script.Handlers.Options; 5 | 6 | namespace TSLab.Script.Handlers 7 | { 8 | [HandlerCategory(HandlerCategories.VolumeAnalysis)] 9 | [HelperName("Volume for period", Language = Constants.En)] 10 | [HelperName("Объём за период", Language = Constants.Ru)] 11 | [InputsCount(1)] 12 | [Input(0, TemplateTypes.SECURITY, Name = Constants.SecuritySource)] 13 | [OutputsCount(1)] 14 | [OutputType(TemplateTypes.DOUBLE)] 15 | [Description("Объём за период (суммарный или средний)")] 16 | [HelperDescription("Volume for period (total or average)", Constants.En)] 17 | public sealed class VolumeForPeriodHandler : ValueForPeriodHandler 18 | { 19 | protected override double GetValue(ISecurity security, int barIndex) 20 | { 21 | return security.Bars[barIndex].Volume; 22 | } 23 | } 24 | } 25 | --------------------------------------------------------------------------------