这是我的自定义指标,它只是修改后的 TDI 指标:
using System.Drawing;
using System.Linq;
using TradingPlatform.BusinessLayer;
namespace Trend
{
public class Sniper : Indicator, IWatchlistIndicator
{
#region Parameters
[InputParameter("RSI period", 10, 1, 9999)]
public int Period = 13;
[InputParameter("Sources prices for the RSI line", 20, variants: new object[] {
"Close", PriceType.Close,
"Open", PriceType.Open,
"High", PriceType.High,
"Low", PriceType.Low,
"Typical", PriceType.Typical,
"Medium", PriceType.Median,
"Weighted", PriceType.Weighted,
"Volume", PriceType.Volume,
"Open interest", PriceType.OpenInterest
})]
public PriceType SourcePrice = PriceType.Close;
[InputParameter("Type of the RSI line", 30, variants: new object[] {
"Simple", RSIMode.Simple,
"Exponential", RSIMode.Exponential}
)]
public RSIMode RSIMode = RSIMode.Exponential;
[InputParameter("Volatility Band", 40, 1, 999)]
public int VolatilityBand = 34;
[InputParameter("Standard Deviation", 50, 0.1, 100.0, 0.1, 2)]
public double StandardDeviation = 1.6185;
[InputParameter("Fast MA period on RSI", 60, 1, 9999)]
public int FastMaOnRSIPeriod = 2;
[InputParameter("Fast MA type on RSI", 60, variants: new object[] {
"Simple", MaMode.SMA,
"Exponential", MaMode.EMA,
"Smoothed Modified", MaMode.SMMA,
"Linear Weighted", MaMode.LWMA}
)]
public MaMode FastMAOnRSIMode = MaMode.SMA;
//
[InputParameter("Calculation type", 90, variants: new object[]
{
"All available data", IndicatorCalculationType.AllAvailableData,
"By period", IndicatorCalculationType.ByPeriod,
})]
public IndicatorCalculationType CalculationType = Indicator.DEFAULT_CALCULATION_TYPE;
#endregion Parameters
private Indicator rsi;
private Indicator bb;
private HistoricalDataCustom historicalDataBB;
private Indicator priceMa;
private HistoricalDataCustom historicalDataPrice;
public override string SourceCodeLink => "https://github.com/Quantower/Scripts/blob/main/Indicators/IndicatorTradersDynamicIndex.cs";
/// <summary>
/// Indicator's constructor. Contains general information: name, description, LineSeries etc.
/// </summary>
public Sniper()
: base()
{
// Defines indicator's name and description.
Name = "Sniper";
Description = "";
// Defines line on demand with particular parameters.
AddLineSeries("BB Up", Color.Orange, 1, LineStyle.Solid);
AddLineSeries("BB Down", Color.Orange, 1, LineStyle.Solid);
AddLineSeries("Fast MA on RSI", Color.White, 1, LineStyle.Solid);
AddLineLevel(68, "", Color.Gray, 1, LineStyle.Dash);
AddLineLevel(32, "", Color.Gray, 1, LineStyle.Dash);
SeparateWindow = true;
}
public int MinHistoryDepths => Enumerable.Max(new int[] { VolatilityBand, FastMaOnRSIPeriod }) + Period;
public override string ShortName => $"Sniper ({Period}: {VolatilityBand}: {FastMaOnRSIPeriod})";
/// <summary>
/// This function will be called after creating an indicator as well as after its input params reset or chart (symbol or timeframe) updates.
/// </summary>
protected override void OnInit()
{
rsi = Core.Indicators.BuiltIn.RSI(Period, SourcePrice, RSIMode, MaMode.SMA, 1);
bb = Core.Indicators.BuiltIn.BB(VolatilityBand, StandardDeviation, PriceType.Close, MaMode.SMA);
historicalDataBB = new HistoricalDataCustom(this);
historicalDataBB.AddIndicator(bb);
priceMa = Core.Indicators.BuiltIn.MA(FastMaOnRSIPeriod, PriceType.Close, FastMAOnRSIMode, this.CalculationType);
historicalDataPrice = new HistoricalDataCustom(this);
historicalDataPrice.AddIndicator(priceMa);
AddIndicator(rsi);
}
/// <summary>
/// Calculation entry point. This function is called when a price data updates.
/// Will be runing under the HistoricalBar mode during history loading.
/// Under NewTick during realtime.
/// Under NewBar if start of the new bar is required.
/// </summary>
/// <param name="args">Provides data of updating reason and incoming price.</param>
protected override void OnUpdate(UpdateArgs args)
{
if (this.Count < this.Period)
return;
historicalDataBB[PriceType.Close] = rsi.GetValue();
historicalDataPrice[PriceType.Close] = rsi.GetValue();
double fastMAonRSI = priceMa.GetValue();
double bbUp = bb.GetValue(0, 0);
double bbDown = bb.GetValue(0, 2);
if (this.Count < this.MinHistoryDepths)
return;
SetValue(bbUp, 0);
SetValue(bbDown, 1);
SetValue(fastMAonRSI, 2);
if (fastMAonRSI > bbUp)
{
LinesSeries[2].SetMarker(0, new IndicatorLineMarker(Color.Red, upperIcon: IndicatorLineMarkerIconType.DownArrow));
}
else if(fastMAonRSI < bbDown)
{
LinesSeries[2].SetMarker(0, new IndicatorLineMarker(Color.Green, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
}
else
{
LinesSeries[2].RemoveMarker(0);
}
}
}
}
这是我的策略:
// Copyright QUANTOWER LLC. © 2017-2022. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using TradingPlatform.BusinessLayer;
namespace Scalpie
{
public class Scalpie : Strategy, ICurrentAccount, ICurrentSymbol
{
[InputParameter("Symbol", 0)]
public Symbol CurrentSymbol { get; set; }
/// <summary>
/// Account to place orders
/// </summary>
[InputParameter("Account", 1)]
public Account CurrentAccount { get; set; }
/// <summary>
/// Period to load history
/// </summary>
[InputParameter("Period", 5)]
private Period period = Period.MIN5;
/// <summary>
/// Period for Fast MA indicator
/// </summary>
[InputParameter("Fast MA", 2, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)]
public int FastMA = 5;
/// <summary>
/// Period for Slow MA indicator
/// </summary>
[InputParameter("Slow MA", 3, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)]
public int SlowMA = 10;
/// <summary>
/// Quantity to open order
/// </summary>
[InputParameter("Quantity", 4, 0.1, 99999, 0.1, 2)]
public double Quantity = 1.0;
public override string[] MonitoringConnectionsIds => new string[] { this.CurrentSymbol?.ConnectionId, this.CurrentAccount?.ConnectionId };
private Indicator indicatorFastMA;
private Indicator indicatorSlowMA;
private HistoricalData hdm;
private int longPositionsCount;
private int shortPositionsCount;
private string orderTypeId;
private bool waitOpenPosition;
private bool waitClosePositions;
public Scalpie()
: base()
{
this.Name = "Scalpie";
this.Description = "scalping strat automated";
}
protected override void OnRun()
{
this.Log("Test message");
// Restore account object from acive connection
if (this.CurrentAccount != null && this.CurrentAccount.State == BusinessObjectState.Fake)
this.CurrentAccount = Core.Instance.GetAccount(this.CurrentAccount.CreateInfo());
// Restore symbol object from acive connection
if (this.CurrentSymbol != null && this.CurrentSymbol.State == BusinessObjectState.Fake)
this.CurrentSymbol = Core.Instance.GetSymbol(this.CurrentSymbol.CreateInfo());
if (this.CurrentSymbol == null || this.CurrentAccount == null || this.CurrentSymbol.ConnectionId != this.CurrentAccount.ConnectionId)
{
this.Log("Incorrect input parameters... Symbol or Account are not specified or they have different connectionID.", StrategyLoggingLevel.Error);
return;
}
this.orderTypeId = Core.OrderTypes.FirstOrDefault(x => x.ConnectionId == this.CurrentSymbol.ConnectionId && x.Behavior == OrderTypeBehavior.Market).Id;
if (string.IsNullOrEmpty(this.orderTypeId))
{
this.Log("Connection of selected symbol has not support market orders", StrategyLoggingLevel.Error);
return;
}
this.indicatorFastMA = Core.Instance.Indicators.BuiltIn.SMA(this.FastMA, PriceType.Close);
this.indicatorSlowMA = Core.Instance.Indicators.BuiltIn.SMA(this.SlowMA, PriceType.Close);
this.hdm = this.CurrentSymbol.GetHistory(this.period, this.CurrentSymbol.HistoryType, Core.TimeUtils.DateTimeUtcNow.AddDays(-100));
Core.PositionAdded += this.Core_PositionAdded;
Core.PositionRemoved += this.Core_PositionRemoved;
Core.OrdersHistoryAdded += this.Core_OrdersHistoryAdded;
this.hdm.HistoryItemUpdated += this.Hdm_HistoryItemUpdated;
this.hdm.AddIndicator(this.indicatorFastMA);
this.hdm.AddIndicator(this.indicatorSlowMA);
}
protected override void OnStop()
{
Core.PositionAdded -= this.Core_PositionAdded;
Core.PositionRemoved -= this.Core_PositionRemoved;
Core.OrdersHistoryAdded -= this.Core_OrdersHistoryAdded;
if (this.hdm != null)
{
this.hdm.HistoryItemUpdated -= this.Hdm_HistoryItemUpdated;
this.hdm.Dispose();
}
base.OnStop();
}
protected override List<StrategyMetric> OnGetMetrics()
{
var result = base.OnGetMetrics();
// An example of adding custom strategy metrics:
result.Add("Total long positions", this.longPositionsCount.ToString());
result.Add("Total short positions", this.shortPositionsCount.ToString());
return result;
}
private void Core_PositionAdded(Position obj)
{
var positions = Core.Instance.Positions.Where(x => x.Symbol == this.CurrentSymbol && x.Account == this.CurrentAccount).ToArray();
this.longPositionsCount = positions.Count(x => x.Side == Side.Buy);
this.shortPositionsCount = positions.Count(x => x.Side == Side.Sell);
double currentPositionsQty = positions.Sum(x => x.Side == Side.Buy ? x.Quantity : -x.Quantity);
if (Math.Abs(currentPositionsQty) == this.Quantity)
this.waitOpenPosition = false;
}
private void Core_PositionRemoved(Position obj)
{
var positions = Core.Instance.Positions.Where(x => x.Symbol == this.CurrentSymbol && x.Account == this.CurrentAccount).ToArray();
this.longPositionsCount = positions.Count(x => x.Side == Side.Buy);
this.shortPositionsCount = positions.Count(x => x.Side == Side.Sell);
if (!positions.Any())
this.waitClosePositions = false;
}
private void Core_OrdersHistoryAdded(OrderHistory obj)
{
if (obj.Symbol == this.CurrentSymbol)
return;
if (obj.Account == this.CurrentAccount)
return;
if (obj.Status == OrderStatus.Refused)
this.ProcessTradingRefuse();
}
private void Hdm_HistoryItemUpdated(object sender, HistoryEventArgs e) => this.OnUpdate();
private void OnUpdate()
{
var positions = Core.Instance.Positions.Where(x => x.Symbol == this.CurrentSymbol && x.Account == this.CurrentAccount).ToArray();
if (this.waitOpenPosition)
return;
if (this.waitClosePositions)
return;
this.Log("Test message");
if (positions.Any())
{
if (this.indicatorFastMA.GetValue(1) < this.indicatorSlowMA.GetValue(1) || this.indicatorFastMA.GetValue(1) > this.indicatorSlowMA.GetValue(1))
{
this.waitClosePositions = true;
this.Log($"Start close positions ({positions.Length})");
foreach (var item in positions)
{
var result = item.Close();
if (result.Status == TradingOperationResultStatus.Failure)
this.ProcessTradingRefuse();
else
this.Log($"Position was close: {result.Status}", StrategyLoggingLevel.Trading);
}
}
}
else
{
if (this.indicatorFastMA.GetValue(2) < this.indicatorSlowMA.GetValue(2) && this.indicatorFastMA.GetValue(1) > this.indicatorSlowMA.GetValue(1))
{
this.waitOpenPosition = true;
this.Log("Start open buy position");
//var result = Core.Instance.PlaceOrder(new PlaceOrderRequestParameters()
//{
// Account = this.CurrentAccount,
// Symbol = this.CurrentSymbol,
// OrderTypeId = this.orderTypeId,
// Quantity = this.Quantity,
// Side = Side.Buy,
//});
//if (result.Status == TradingOperationResultStatus.Failure)
// this.ProcessTradingRefuse();
//else
// this.Log($"Position open: {result.Status}", StrategyLoggingLevel.Trading);
}
else if (this.indicatorFastMA.GetValue(2) > this.indicatorSlowMA.GetValue(2) && this.indicatorFastMA.GetValue(1) < this.indicatorSlowMA.GetValue(1))
{
this.waitOpenPosition = true;
this.Log("Start open sell position");
//var result = Core.Instance.PlaceOrder(new PlaceOrderRequestParameters()
//{
// Account = this.CurrentAccount,
// Symbol = this.CurrentSymbol,
// OrderTypeId = this.orderTypeId,
// Quantity = this.Quantity,
// Side = Side.Sell,
//});
//if (result.Status == TradingOperationResultStatus.Failure)
// this.ProcessTradingRefuse();
//else
// this.Log($"Position open: {result.Status}", StrategyLoggingLevel.Trading);
}
}
}
private void ProcessTradingRefuse()
{
this.Log("Strategy have received refuse for trading action. It should be stopped", StrategyLoggingLevel.Error);
this.Stop();
}
}
}
我想将我的指标值纳入我的策略。请帮助。
我试图只实例化指标的类名,但它说它是未定义的。 智能感知对我大喊大叫。我还尝试复制策略文件中的指标代码,但没有任何结果。