Merhaba alttaki varsayılan Pmax Stratejinin sat koşulunu aşağıdaki gibi güncellemek istiyorum yardımlarınızı rica ederim.
Sat koşulu
Varsayılanda olan : mov, pmax i aşağı keserse
Benim istediğim : "mov, pmax i aşağı keserse" veya " eğer mov > pmax ve bar close < pmax" --- Hangisi önce olursa..
Sonuç olarak strateji hala "al" pozisyonundayken son bar pmax in altında kapanış yaparsa "sat" istiyorum.
Gözlemlerime göre çok büyük olasılıkla pmax altında bar kapanışı olduğunda strateji 1 ve 2 bar sonra sat veriyor.
Dolayısıyla "zarar kes" 1 veya 2 bar geç kalıyor. Yada böyle bir durumda genellikle grafik yatay seyrediyor.
Poziyson yatay seyirde yüksek olasılıkla zarar ediyor.. Amaç bu durumlardan erken kaçmak..
Bu olasılıkta "sat" verdikten sonra pozisyon hala "al" olarak devam edebiliyor ve sonraki yükselişte kaçırılmış bir fırsat olarak önünümze gelebilir. Ancak bu olasılıkta incelediğim grafiklerde nadiren gördüm.
Risk/Ödül oranına göre benim istediğim şekilde sat koşulları eklenirse risk az ödül daha yüksek olacak düşüncesindeyim.
Kullanmak isteyen arkadaşlar olursa düşüncelerimi de aktarmak istedim. Farklı düşüncelerle de geliştirilebilir.
İyi çalışmalar.
using System;
using System.Collections.Generic;
using System.Linq;
using Matriks.Data.Symbol;
using System.Windows.Media;
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*******************************************************//
//Gecici sinyal ile kullaniniz. bufferlength strateji canli calistirildiginda averajlarin onceden hesaplanarak gelmesini//
//saglamaktadir. 200'un altina dusurmeyiniz. Hareketli ortalama PMAX in uzerinde kirdiginda alim, altina kirdiginda //
//satim yapilmaktadir. Sirali emir gonderimi aktiftir (Strateji ilk olarak alim emri bekleyecek ve sirayla gidecektir) //
namespace Matriks.Lean.Algotrader
{
public class PMAX_strat_buffer_release : 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("BTC_USDT_BIN")]
public string Symbol;
[Parameter(SymbolPeriod.Min)]
public SymbolPeriod SymbolPeriod;
[Parameter(5)]
public decimal BuySellQuantity;
[Parameter(14)]
public int AtrPeriod;
[Parameter(8)]
public int MovPeriod;
[Parameter(2)]
public decimal Coeff;
[Parameter(MovMethod.E)]
public MovMethod MovMethod;
public bool firstrun = true;
int bufferlength = 200;
WILDERS wilders;
MOV mov;
/// <summary>
/// Strateji ilk çalıştırıldığında bu fonksiyon tetiklenir. Tüm sembole kayit işlemleri,
/// indikator ekleme, haberlere kayıt olma işlemleri burada yapılır.
/// </summary>
public override void OnInit()
{
AddSymbol(Symbol, SymbolPeriod);
wilders = new WILDERS(AtrPeriod);
mov = new MOV(MovPeriod, MovMethod);
// Algoritmanın kalıcı veya geçici sinyal ile çalışıp çalışmayacağını belirleyen fonksiyondur.
// true geçerseniz algoritma sadece yeni bar açılışlarında çalışır, bu fonksiyonu çağırmazsanız veya false geçerseniz her işlem olduğunda algoritma tetiklenir.
WorkWithPermanentSignal(false);
//Eger 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(true);
}
Dictionary<int, decimal> fubDict = new Dictionary<int, decimal>();
Dictionary<int, decimal> flbDict = new Dictionary<int, decimal>();
Dictionary<int, decimal> PMAX_Dict = new Dictionary<int, decimal>();
/// <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 currentBar = barDataCurrentValues.LastUpdate.BarDataIndex;
if (currentBar < AtrPeriod)
{
fubDict[currentBar] = 0;
flbDict[currentBar] = 0;
PMAX_Dict[currentBar] = 0;
return ;
}
if (firstrun)
{
int i = bufferlength;
fubDict[currentBar - i -1] = 0;
flbDict[currentBar - i -1] = 0;
PMAX_Dict[currentBar - i -1] = 0;
var _barData_ = GetBarData();
if (currentBar - 1 < 0 || !_barData_.Close.ContainsKey(currentBar - 1)) return ;
Debug("currentBar = " + currentBar + ", buffer LENGTH = " + bufferlength + " indikator buffer hesaplaniyor");
for (; i >= 0; i--)
{
var _high_ = _barData_.High[currentBar - i];
var _low_ = _barData_.Low[currentBar - i];
var _diff_ = _high_ - _low_;
var _range2_ = Math.Abs(_high_ - _barData_.Close[currentBar - 1 - i]);
var _range3_ = Math.Abs(_low_ - _barData_.Close[currentBar - 1 - i]);
var _value_ = Math.Max(_diff_, Math.Max(_range2_, _range3_));
wilders.Update(_value_, currentBar - i, _barData_.Time[currentBar - i]);
mov.Update((_high_ + _low_) / 2, (currentBar - i), _barData_.Time[currentBar - i]);
//Debug($"mov Updated: with value: {(_high_ + _low_) / 2}, @{currentBar - i}, with TIME = {_barData_.Time[currentBar - i]}");
var _k = mov.Value[0][currentBar - i];
var _offset = Coeff * wilders.CurrentValue;
var _str = _k + _offset;
var _sts = _k - _offset;
var _prev = PMAX_Dict[currentBar - i -1];
var _fub = _str<_prev || mov.Value[0][currentBar -1 - i] >_prev? _str:_prev;
var _flb = _sts>_prev || mov.Value[0][currentBar -1 - i] <_prev? _sts:_prev;
fubDict[currentBar - i] = _fub;
flbDict[currentBar - i] = _flb;
var _pmax = _prev == fubDict[currentBar - i -1] && _k < _fub? _fub : (_prev == fubDict[currentBar - i -1] && _k>_fub? _flb:(_prev == flbDict[currentBar - i -1] && _k>_flb? _flb
:(_prev == flbDict[currentBar - i -1] && _k < _flb? _fub:_fub)));
PMAX_Dict[currentBar - i] = _pmax;
//Debug($"PMAX = {Math.Round(_pmax,4)}, mov = {Math.Round(mov.Value[0][currentBar-i],4)}, @{currentBar - i}");
}
firstrun = false;
}
else
{
var barData = GetBarData();
if (currentBar - 1 < 0 || !barData.Close.ContainsKey(currentBar - 1)) return ;
var high = barData.High[currentBar];
var low = barData.Low[currentBar];
var diff = high - low;
var range2 = Math.Abs(high - barData.Close[currentBar - 1]);
var range3 = Math.Abs(low - barData.Close[currentBar - 1]);
var value = Math.Max(diff, Math.Max(range2, range3));
wilders.Update(value, currentBar, barDataCurrentValues.LastUpdate.DTime);
mov.Update((high + low) / 2, currentBar, barDataCurrentValues.LastUpdate.DTime);
var k = mov.CurrentValue;
var offset = Coeff * wilders.CurrentValue;
var str = k + offset;
var sts = k - offset;
var prev = PMAX_Dict[currentBar -1];
var fub = str<prev || mov.Value[0][currentBar -1] >prev? str:prev;
var flb = sts>prev || mov.Value[0][currentBar -1] <prev? sts:prev;
fubDict[currentBar] = fub;
flbDict[currentBar] = flb;
var pmax = prev == fubDict[currentBar -1] && k<fub? fub : (prev == fubDict[currentBar -1] && k>fub? flb:(prev == flbDict[currentBar -1] && k>flb? flb
:(prev == flbDict[currentBar -1] && k<flb? fub:fub)));
PMAX_Dict[currentBar] = pmax;
if (barDataCurrentValues.LastUpdate.IsNewBar == true)
{
Debug($"PMAX = {Math.Round(pmax,4)}, mov = {Math.Round(mov.Value[0][currentBar],4)}");
if (mov.Value[0][currentBar -1] <PMAX_Dict[currentBar -1] && mov.Value[0][currentBar] > PMAX_Dict[currentBar])
{
SendMarketOrder(Symbol, BuySellQuantity, OrderSide.Buy);
Debug("Alış emri gönderildi");
}
if (PMAX_Dict[currentBar -1] <mov.Value[0][currentBar -1] && PMAX_Dict[currentBar] >mov.Value[0][currentBar])
{
SendMarketOrder(Symbol, BuySellQuantity, OrderSide.Sell);
Debug("Satış emri gönderildi");
}
}
}
}
/// <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)
{
}
}
}
}