Merhaba,
Hazır stratejilerdeki HeikenAshi_Bitmex stratejisini inceleyebilirsiniz.
Kodu tekrar buraya ekliyorum.
using System;
using System.Collections.Generic;
using System.Linq;
using Matriks.Data.Symbol;
using Matriks.Engines;
using Matriks.Indicators;
using Matriks.Symbols;
using Matriks.AlgoTrader;
using Matriks.Trader.Core;
using Matriks.Trader.Core.Fields;
using Matriks.Trader.Core.TraderModels;
using Matriks.Lean.Algotrader.AlgoBase;
using Matriks.Lean.Algotrader.Models;
using Matriks.Lean.Algotrader.Trading;
//*******************************************************ACIKLAMA*******************************************************//
//HeikenAshi stratejisinin Bitmex (LONG/SHORT yapilabilen butun enstrumanlarda kullanilabilir) versiyonudur. Heiken-ashi//
//barlarini hesaplayarak, pozitif (kapanis>acilis) barlarda alim, negatif (kapanis<acilis) barlarda aciga satis yapar. //
//Barlarin strateji calistiktan sonra dogru sekilde hesaplanmis olmasi icin bufferlength ile belirlenen sayida bar //
//geriye giderek barlari hesaplamaya baslar. //
namespace Matriks.Lean.Algotrader
{
public class HeikenAshi_Bitmex : MatriksAlgo
{
// Strateji çalıştırılırken kullanacağımız parametreler. Eğer sembolle ilgili bir parametre ise,
// "SymbolParameter" ile, değilse "Parameter" ile tanımlama yaparız. Parantez içindeki değerler default değerleridir.
[SymbolParameter("XBT_USD_BMEX")]
public string Symbol;
[Parameter(100)]
public int Quantity;
[Parameter(SymbolPeriod.Min)]
public SymbolPeriod SymbolPeriod;
public bool FirstBar = true;
public int Position = 0;
decimal HA_Open = 0; //(open of previous bar + close of previous bar)/2
decimal HA_High = 0; //the maximum value from the high, open, or close of the current period
decimal HA_Low = 0; // minimum value from the low, open, or close of the current period
decimal HA_Close = 0;
int bufferlength = 30;
decimal _open_ = 0, _high_ = 0, _low_ = 0, _close_ = 0;
public override void OnInit()
{
AddSymbol(Symbol, SymbolPeriod);
//Eger backtestte emri bir al bir sat seklinde gonderilmesi isteniyor bu true set edilir.
//Alttaki satırı silerek veya false geçerek emirlerin sirayla gönderilmesini engelleyebilirsiniz.
SendOrderSequential(false);
WorkWithPermanentSignal(true);
}
/// <summary>
/// Init islemleri tamamlaninca, bardatalar kullanmaya hazir hale gelince bu fonksiyon tetiklenir. Data uzerinde bir defa yapilacak islemler icin kullanilir
/// </summary>
public override void OnInitComplated()
{
}
/// <summary>
/// Eklenen sembollerin bardata'ları ve indikatorler güncellendikçe bu fonksiyon tetiklenir.
/// </summary>
/// <param name="barData">Bardata ve hesaplanan gerçekleşen işleme ait detaylar</param>
public override void OnDataUpdate(BarDataCurrentValues barDataCurrentValues)
{
var barDataModel = GetBarData(Symbol, SymbolPeriod);
var open = barDataModel.Open[barDataCurrentValues.LastUpdate.BarDataIndex - 1]; //barDataCurrentValues.LastUpdate.Open[barData.BarDataIndex -1]; //barDataModel.Open[barData.BarDataIndex -1];
var high = barDataModel.High[barDataCurrentValues.LastUpdate.BarDataIndex - 1];
var low = barDataModel.Low[barDataCurrentValues.LastUpdate.BarDataIndex - 1];
var close = barDataModel.Close[barDataCurrentValues.LastUpdate.BarDataIndex - 1];
Debug(open + ", " + high + ", " + low + ", " + close);
//10 bar BUFFER
if (FirstBar)
{
Debug(bufferlength + " bar buffer hesaplaniyor");
for (int i = bufferlength; i >= 0; i--)
{
_open_ = Ref(barDataModel, OHLCType.Open, i);
_high_ = Ref(barDataModel, OHLCType.High, i);
_low_ = Ref(barDataModel, OHLCType.Low, i);
_close_ = Ref(barDataModel, OHLCType.Close, i);
HA_Open = i == bufferlength ? (_open_ + _close_) / 2 : HA_Open = (HA_Open + HA_Close) / 2; //at first iteration calculate HA_Open accordingly
HA_Close = (_open_ + _high_ + _low_ + _close_) / 4;
HA_High = Math.Max(_high_, Math.Max(HA_Open, HA_Close));
HA_Low = Minimum(_low_, Math.Max(HA_Open, HA_Close));
//Debug($"({i+1} : _open_ = {_open_} , _high_= {_high_}, _low_ = {_low_}, _close_ = {_close_})");
if (HA_Close > HA_Open)
Debug($"({i + 1} bar onceki fiyatlar: HA_Open = {Math.Round(HA_Open, 1)} , HA_Close= {HA_Close}, HA_High = {Math.Round(HA_High, 1)}, HA_Low = {HA_Low}. Bar POSITIVE)");
else
Debug($"({i + 1} bar onceki fiyatlar: HA_Open = {Math.Round(HA_Open, 1)} , HA_Close= {HA_Close}, HA_High = {Math.Round(HA_High, 1)}, HA_Low = {HA_Low}. Bar NEGATIVE)");
}
FirstBar = false;
}
else
{
HA_Open = (HA_Open + HA_Close) / 2;
HA_Close = (open + high + low + close) / 4;
HA_High = Math.Max(high, Math.Max(HA_Open, HA_Close));
HA_Low = Minimum(low, Math.Max(HA_Open, HA_Close));
}
if (HA_Close > HA_Open)
{
Debug($"HA_Close: {HA_Close} > HA_Open: {Math.Round(HA_Open, 2)}. Bar POSITIVE");
if (Position == 0)
{
SendMarketOrder(Symbol, Quantity, OrderSide.Buy);
Position++;
Debug("Alis emri gonderildi. Pozisyon = " + Position);
}
else if (Position == -1)
{
SendMarketOrder(Symbol, Quantity * 2, OrderSide.Buy);
Position += 2;
Debug("Alis emri gonderildi. Pozisyon = " + Position);
}
}
if (HA_Close < HA_Open)
{
Debug($"HA_Close: {HA_Close} < HA_Open: {Math.Round(HA_Open, 2)}. Bar NEGATIVE");
if (Position == 0)
{
SendMarketOrder(Symbol, Quantity, OrderSide.Sell);
Position--;
Debug("Satis emri gonderildi. Pozisyon = " + Position);
}
else if (Position == 1)
{
SendMarketOrder(Symbol, Quantity * 2, OrderSide.Sell);
Position -= 2;
Debug("Satis emri gonderildi. Pozisyon = " + Position);
}
}
}
/// <summary>
/// Gönderilen emirlerin son durumu değiştikçe bu fonksiyon tetiklenir.
/// </summary>
/// <param name="barData">Emrin son durumu</param>
public override void OnOrderUpdate(IOrder order)
{
if (order.OrdStatus.Obj == OrdStatus.Filled)
{
}
}
}
}