在 GitHub 上查看

LotScalp 策略

该策略每天在指定的小时根据过去K线开盘价之间的差值开仓一次。

工作原理

  1. 等待交易时间:策略监控K线的开盘时间,一旦当前小时大于 TradeTime,下一次达到该小时即可允许交易。
  2. 信号生成
    • 当当前小时等于 TradeTime 时,比较 t1 根之前的开盘价与 t2 根之前的开盘价。
    • 如果 Open[t1] - Open[t2] 大于 DeltaShort 点,则开空单。
    • 如果 Open[t2] - Open[t1] 大于 DeltaLong 点,则开多单。
  3. 持仓管理
    • 多单在价格上升 TakeProfitLong 点或下跌 StopLossLong 点时平仓。
    • 空单在价格下跌 TakeProfitShort 点或上升 StopLossShort 点时平仓。
    • 若持仓时间超过 MaxOpenTime 小时,也会强制平仓。

策略使用固定交易量,每天仅交易一次。

参数

名称 说明
CandleType 使用的K线类型。
Volume 下单手数。
TakeProfitLong 多单止盈点数。
StopLossLong 多单止损点数。
TakeProfitShort 空单止盈点数。
StopLossShort 空单止损点数。
TradeTime 评估信号的小时。
T1 第一个参考开盘价的回溯K线数。
T2 第二个参考开盘价的回溯K线数。
DeltaLong 触发多单所需的点差。
DeltaShort 触发空单所需的点差。
MaxOpenTime 最大持仓时间(小时)。

备注

  • 仅处理已完成的K线。
  • 点数阈值通过合约的最小变动价位转换为实际价格。
  • 策略未使用任何额外指标。
using System;
using System.Collections.Generic;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Scalping strategy comparing past open prices with EMA trend filter.
/// </summary>
public class LotScalpStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevOpen;
	private decimal _prevPrevOpen;
	private int _barCount;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public LotScalpStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period for trend", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle source", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevOpen = 0;
		_prevPrevOpen = 0;
		_barCount = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		SubscribeCandles(CandleType).Bind(ema, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaValue)
	{
		if (candle.State != CandleStates.Finished) return;

		_barCount++;
		var close = candle.ClosePrice;
		var open = candle.OpenPrice;

		if (_barCount >= 3)
		{
			var diff = _prevPrevOpen - _prevOpen;

			// Open prices diverging downward + close above EMA => buy
			if (diff > 0 && close > emaValue && Position <= 0)
			{
				if (Position < 0) BuyMarket();
				BuyMarket();
			}
			// Open prices diverging upward + close below EMA => sell
			else if (diff < 0 && close < emaValue && Position >= 0)
			{
				if (Position > 0) SellMarket();
				SellMarket();
			}
		}

		_prevPrevOpen = _prevOpen;
		_prevOpen = open;
	}
}