Стратегия использует осциллятор Center of Gravity OSMA для поиска разворотов тренда.
Осциллятор умножает простую и взвешенную скользящие средние, дважды сглаживает результат и
отслеживает изменение направления. Когда значение после снижения начинает расти, закрываются
короткие позиции и при необходимости открывается длинная. Когда после роста значение разворачивается
вниз, длинные позиции закрываются и при необходимости открывается короткая.
Принцип работы
В качестве входа используется цена закрытия.
Индикатор выполняет:
расчёт простой скользящей средней (SMA) с периодом Period;
расчёт взвешенной скользящей средней (WMA) с тем же периодом;
перемножение полученных средних;
два дополнительных сглаживания с периодами SmoothPeriod1 и SmoothPeriod2.
Правила торговли:
если предыдущее значение меньше ещё более раннего, а текущее значение больше предыдущего — осциллятор развернулся вверх; короткая позиция закрывается, и может открыться длинная;
если предыдущее значение больше ещё более раннего, а текущее значение меньше предыдущего — осциллятор развернулся вниз; длинная позиция закрывается, и может открыться короткая;
параметры StopLoss и TakeProfit задают уровни защиты в ценовых единицах.
Параметры
Period – базовый период для SMA и WMA;
SmoothPeriod1 – период первого сглаживания;
SmoothPeriod2 – период второго сглаживания;
StopLoss – расстояние стоп‑лосса (0 – отключён);
TakeProfit – расстояние тейк‑профита (0 – отключён);
BuyPosOpen – разрешить открытие длинных позиций;
SellPosOpen – разрешить открытие коротких позиций;
BuyPosClose – закрывать длинные позиции по сигналу на продажу;
SellPosClose – закрывать короткие позиции по сигналу на покупку;
CandleType – тип свечей (таймфрейм) для расчётов.
Примечания
Представлена только C# версия, папка Python отсутствует.
При изменении кода используйте табуляцию для отступов.
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>
/// Center of Gravity OSMA strategy.
/// Uses SMA vs WMA difference (center of gravity concept) direction changes for signals.
/// </summary>
public class CenterOfGravityOsmaStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevOsma;
private decimal _prevPrevOsma;
private int _count;
public int Period { get => _period.Value; set => _period.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public CenterOfGravityOsmaStrategy()
{
_period = Param(nameof(Period), 10)
.SetGreaterThanZero()
.SetDisplay("Period", "Calculation period", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevOsma = 0;
_prevPrevOsma = 0;
_count = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = Period };
var wma = new WeightedMovingAverage { Length = Period };
SubscribeCandles(CandleType)
.Bind(sma, wma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue, decimal wmaValue)
{
if (candle.State != CandleStates.Finished)
return;
var osma = smaValue - wmaValue;
_count++;
if (_count < 3)
{
_prevPrevOsma = _prevOsma;
_prevOsma = osma;
return;
}
// Buy when OSMA turns up
var turnUp = _prevOsma < _prevPrevOsma && osma > _prevOsma;
// Sell when OSMA turns down
var turnDown = _prevOsma > _prevPrevOsma && osma < _prevOsma;
if (turnUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (turnDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevPrevOsma = _prevOsma;
_prevOsma = osma;
}
}