在 GitHub 上查看
Connect Disconnect Sound Alert 策略
概述
Connect Disconnect Sound Alert Strategy 持续检测策略连接器的在线状态,并在每次连接或断开时记录详细日志。原始的 MQL5 专家在 MetaTrader 终端连接状态变化时播放声音。C# 版本保留了这一核心思想——发现连接变化——并利用 StockSharp 的日志系统提供更加丰富的诊断信息,因此可以作为监控连接稳定性的轻量级工具。
主要特点
- 以可配置的周期轮询连接器状态。
- 捕获连接与断开事件,并写入详细日志。
- 可选记录每次在线或离线持续的时间长度。
- 首次检测时不触发声音提醒,以保持与 MQL 版本一致的行为。
参数
| 名称 |
默认值 |
说明 |
CheckIntervalSeconds |
1 |
两次状态检查之间的秒数,必须大于零。 |
LogDurations |
true |
若启用,则在每次状态切换后记录上一状态持续的时间。 |
所有参数均通过 StrategyParam<T> 暴露,可在界面或优化器中调整。
工作流程
- 启动时保存当前连接状态,并输出初始状态日志。
- 使用
System.Threading.Timer 定期调用处理函数,对比当前状态与上一次状态。
- 一旦发现变化,就写入日志。第一次通知会标记为“initial”,仅用于同步状态,不表示真正的报警。
- 如果启用了持续时间记录,则会指出上一次在线或离线持续了多久,方便评估连接质量。
- 在停止或重置时自动释放计时器,避免后台任务遗留。
使用建议
- 将策略附加到任何支持连接器的 StockSharp 终端,它不会订阅行情或发送订单。
- 默认 1 秒的轮询间隔适合实时监控,如需降低负载可适当增加间隔。
- 日志通过
LogInfo 输出,可将其接入日志查看器或通知系统;需要声音提醒时,可在宿主程序中监听这些日志并播放音频。
安全性提示
- 策略会验证轮询间隔的合法性,若不符合要求会抛出异常。
- 使用
CurrentTime 生成时间戳,兼容实时和历史回放环境。
- 在停止或重置时会正确释放计时器,避免出现悬挂线程。
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Connection alert strategy with SMA crossover trading.
/// Buys when fast SMA crosses above slow SMA, sells on cross below.
/// </summary>
public class ConnectDisconnectSoundAlertStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public ConnectDisconnectSoundAlertStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new SimpleMovingAverage { Length = FastPeriod };
var slow = new SimpleMovingAverage { Length = SlowPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, (candle, fastVal, slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class connect_disconnect_sound_alert_strategy(Strategy):
"""
SMA crossover strategy. Buys when fast SMA crosses above slow SMA.
"""
def __init__(self):
super(connect_disconnect_sound_alert_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast SMA", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow SMA", "Slow SMA period", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(connect_disconnect_sound_alert_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
def OnStarted2(self, time):
super(connect_disconnect_sound_alert_strategy, self).OnStarted2(time)
fast = SimpleMovingAverage()
fast.Length = self._fast_period.Value
slow = SimpleMovingAverage()
slow.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def on_process(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast != 0.0 and self._prev_slow != 0.0:
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return connect_disconnect_sound_alert_strategy()