使用 StockSharp 的高阶绑定接口 (SubscribeCandles().Bind(...)) 获取 AO 值,无需手动查询指标。
通过固定长度列表模拟原策略的历史偏移访问,同时避免直接调用指标准值。
根据需求未提供 Python 版本。
未对测试项目做出改动。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Perceptron-based strategy using Awesome Oscillator values at different lookback periods.
/// Combines weighted AO signals with price pattern confirmation for entry/exit decisions.
/// </summary>
public class N7SAo772012Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _aoPeriod;
private readonly StrategyParam<int> _lookback;
private readonly List<decimal> _aoHistory = new();
private decimal _entryPrice;
public N7SAo772012Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for analysis.", "General");
_aoPeriod = Param(nameof(AoPeriod), 5)
.SetDisplay("AO Period", "Period for the Awesome Oscillator.", "Indicators");
_lookback = Param(nameof(Lookback), 3)
.SetDisplay("Lookback", "Number of AO values to look back for signal.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AoPeriod
{
get => _aoPeriod.Value;
set => _aoPeriod.Value = value;
}
public int Lookback
{
get => _lookback.Value;
set => _lookback.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_aoHistory.Clear();
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ao = new AwesomeOscillator();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ao, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ao);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal aoValue)
{
if (candle.State != CandleStates.Finished)
return;
_aoHistory.Add(aoValue);
if (_aoHistory.Count > 50)
_aoHistory.RemoveAt(0);
if (_aoHistory.Count < Lookback + 1)
return;
var close = candle.ClosePrice;
var current = _aoHistory[_aoHistory.Count - 1];
var prev = _aoHistory[_aoHistory.Count - 1 - Lookback];
// AO momentum: current vs lookback periods ago
var rising = current > prev && current > 0;
var falling = current < prev && current < 0;
// Manage positions
if (Position > 0)
{
// Exit long if AO turns negative or stop-loss
if (current < 0 || (_entryPrice > 0 && close < _entryPrice * 0.98m))
{
SellMarket();
}
}
else if (Position < 0)
{
// Exit short if AO turns positive or stop-loss
if (current > 0 || (_entryPrice > 0 && close > _entryPrice * 1.02m))
{
BuyMarket();
}
}
// Entry
if (Position == 0)
{
if (rising)
{
_entryPrice = close;
BuyMarket();
}
else if (falling)
{
_entryPrice = close;
SellMarket();
}
}
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import AwesomeOscillator
class n7_s_ao772012_strategy(Strategy):
def __init__(self):
super(n7_s_ao772012_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(2))) \
.SetDisplay("Candle Type", "Timeframe for analysis", "General")
self._ao_period = self.Param("AoPeriod", 5) \
.SetDisplay("AO Period", "Period for the Awesome Oscillator", "Indicators")
self._lookback = self.Param("Lookback", 3) \
.SetDisplay("Lookback", "Number of AO values to look back for signal", "Indicators")
self._ao_history = []
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def AoPeriod(self):
return self._ao_period.Value
@property
def Lookback(self):
return self._lookback.Value
def OnStarted2(self, time):
super(n7_s_ao772012_strategy, self).OnStarted2(time)
self._ao_history = []
self._entry_price = 0.0
self._ao = AwesomeOscillator()
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._ao, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ao_value):
if candle.State != CandleStates.Finished:
return
ao_val = float(ao_value)
self._ao_history.append(ao_val)
if len(self._ao_history) > 50:
self._ao_history.pop(0)
lookback = self.Lookback
if len(self._ao_history) < lookback + 1:
return
close = float(candle.ClosePrice)
current = self._ao_history[-1]
prev = self._ao_history[-1 - lookback]
rising = current > prev and current > 0
falling = current < prev and current < 0
# Manage positions
if self.Position > 0:
if current < 0 or (self._entry_price > 0 and close < self._entry_price * 0.98):
self.SellMarket()
elif self.Position < 0:
if current > 0 or (self._entry_price > 0 and close > self._entry_price * 1.02):
self.BuyMarket()
# Entry
if self.Position == 0:
if rising:
self._entry_price = close
self.BuyMarket()
elif falling:
self._entry_price = close
self.SellMarket()
def OnReseted(self):
super(n7_s_ao772012_strategy, self).OnReseted()
self._ao_history = []
self._entry_price = 0.0
def CreateClone(self):
return n7_s_ao772012_strategy()