Versi uji coba dari sebuah algoritma seringkali diperlukan oleh pembuat algoritma untuk mengejar strategi distribusi yang efektif di Toko cTrader. Artikel ini menjelaskan cara memperkenalkan batasan pada versi uji coba cBot, indikator, dan plugin pada tingkat kode.
Kiat
Duplikat algoritma utama Anda untuk membuat versi uji coba, tambahkan batasan seperti yang dijelaskan dalam panduan ini, lalu publikasikan uji coba di Toko cTrader.
Batasan uji coba
Batasan uji coba memastikan bahwa calon pembeli dapat menguji perilaku umum, logika, dan kualitas algoritma Anda, tetapi tidak dapat sepenuhnya mereplikasi fungsionalitas versi berbayar.
Batasan umum dalam kode algoritma uji coba meliputi:
Operasi hanya pada akun demo
Operasi hanya pada backtesting
Batas keuntungan harian
Simbol dan periode yang dikodekan secara tetap
Parameter yang dikodekan secara tetap
Dan lainnya
cBots
Struktur kode dari cBot uji coba mungkin terlihat seperti ini:
1 2 3 4 5 6 7 8 910111213141516171819202122
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{protectedoverridevoidOnStart(){// Trial setup checks (account type, symbol, expiry, etc.)// Restrictions logic for the trial// before or around your normal trading logic.}protectedoverridevoidOnBar(){// Restrictions logic for the trial// before or around your normal trading logic.}privatevoidRunStrategy(){// Normal trading logic goes here// e.g., signal detection, risk management, order placement.}}
1 2 3 4 5 6 7 8 910111213141516171819202122
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():defon_start(self):# Trial setup checks (account type, symbol, expiry, etc.)# Restrictions logic for the trial# before or around your normal trading logic.passdefon_bar(self):# Restrictions logic for the trial# before or around your normal trading logic.passdefrun_strategy(self):# Normal trading logic goes here# e.g., signal detection, risk management, order placement.pass
Hanya demo
Izinkan bot uji coba untuk berjalan hanya pada akun demo. Jika pengguna melampirkannya ke akun live, cBot akan berhenti menjalankan perintah.
1 2 3 4 5 6 7 8 9101112131415161718192021
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{protectedoverridevoidOnStart(){if(Account.IsLive){Print("This trial version can be used only on demo accounts.");Stop();// Stops the cBot for real accountsreturn;}RunStrategy();// <<< Actual trading logic}privatevoidRunStrategy(){// Normal trading logic goes here// e.g., signal detection, risk management, order placement.}}
1 2 3 4 5 6 7 8 910111213141516171819
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():defon_start(self):ifapi.Account.IsLive:print("This trial version can be used only on demo accounts.")api.Stop()# Stops the cBot for real accountsreturnself.run_strategy()# <<< Actual trading logicdefrun_strategy(self):# Normal trading logic goes here# e.g., signal detection, risk management, order placement.pass
Hanya backtesting
Izinkan cBot untuk berfungsi hanya selama backtest. Jika pengguna mencoba menggunakan algoritma untuk trading dalam kondisi nyata, tidak ada yang terjadi.
1 2 3 4 5 6 7 8 9101112131415
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{protectedoverridevoidOnStart(){if(RunningMode==RunningMode.RealTime){Print("This trial version can run only in backtesting mode.");Stop();// Stops cBotreturn;}}// Rest of your cBot logic}
1 2 3 4 5 6 7 8 91011121314
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():defon_start(self):ifapi.RunningMode==RunningMode.RealTime:print("This trial version can run only in backtesting mode.")api.Stop()# Stops cBotreturn# Rest of your cBot logic
Batas keuntungan harian
Programkan cBot untuk berhenti beroperasi begitu keuntungan bersih harian mencapai nilai yang ditetapkan.
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{privateconstdoubleMaxDailyProfit=20.0;protectedoverridevoidOnStart(){StopIfMaxDailyProfitReached();Positions.Closed+=_=>StopIfMaxDailyProfitReached();}privatevoidStopIfMaxDailyProfitReached(){vartodayProfit=History.Where(t=>t.ClosingTime.Date==Server.Time.Date).Sum(t=>t.NetProfit);if(todayProfit<MaxDailyProfit)return;Print("Trial limit reached: daily profit cap.");Stop();// Stops cBot}// Rest of your cBot logic}
1 2 3 4 5 6 7 8 91011121314151617181920212223
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():MaxDailyProfit=20.0defon_start(self):self.stop_if_max_daily_profit_reached()api.Positions.Closed+=lambda_:self.stop_if_max_daily_profit_reached()defstop_if_max_daily_profit_reached(self):todayProfit=[t.NetProfitfortinHistoryift.ClosingTime.Date==api.Server.Time.Date]iftodayProfit<self.MaxDailyProfit:returnprint("Trial limit reached: daily profit cap.")api.Stop();# Stops cBot# Rest of your cBot logic
Simbol dan periode yang dikodekan secara tetap
Jika pengguna mencoba menjalankan cBot pada simbol atau periode lain, tidak ada yang terjadi.
1 2 3 4 5 6 7 8 910111213141516171819202122
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{privateconststringValidSymbolName="EURUSD";privateconststringValidTimeFrame="Hour";protectedoverridevoidOnStart(){StopIfSymbolOrTimeFrameIsInvalid();}privatevoidStopIfSymbolOrTimeFrameIsInvalid(){if(SymbolName==ValidSymbolName&&TimeFrame.Name==ValidTimeFrame)return;Print($"This trial version works only on {ValidSymbolName} {ValidTimeFrame}.");Stop();// Stops cBot}// Rest of your cBot logic}
1 2 3 4 5 6 7 8 9101112131415161718192021
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():ValidSymbolName="EURUSD"ValidTimeFrame="Hour"defon_start(self):self.stop_if_symbol_or_time_frame_is_invalid()defstop_if_symbol_or_time_frame_is_invalid(self):ifapi.SymbolName==self.ValidSymbolNameandapi.TimeFrame.Name==self.ValidTimeFrame:returnprint(f"This trial version works only on {ValidSymbolName}{ValidTimeFrame}.")api.Stop();# Stops cBot# Rest of your cBot logic
Parameter yang dikodekan secara tetap
Kodekan cBot untuk selalu menggunakan konstanta internal yang tidak menguntungkan, seperti volume atau ukuran lot yang kecil.
1 2 3 4 5 6 7 8 910111213
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{// In full version, you might have:// [Parameter("Volume (lots)", DefaultValue = 0.1)]// public double VolumeInLots { get; set; }// In trial version, you can omit parameters entirely// and always use a fixed volume amount when executing trades:privateconststringTrialVolumeInLots=0.01// Rest of your cBot logic}
1 2 3 4 5 6 7 8 9101112131415161718
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():# In full version, you might have:# [Parameter("Volume (lots)", DefaultValue = 0.1)]# public double VolumeInLots { get; set; }# In Python algos you have to define parameters# in C# file of your algo# In trial version, you can omit parameters entirely# and always use a fixed volume amount when executing trades:TrialVolumeInLots=0.01# Rest of your cBot logic
Batas trading harian
Konfigurasikan cBot untuk berhenti trading selama sisa hari setelah jumlah trading tertentu.
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{privateconstintMaxTradesPerDay=5;protectedoverridevoidOnBar(){if(IsMaxDailyTradeReached())return;// Skip trading logic if max trade number reached}privatevoidIsMaxDailyTradeReached(){vartodayTradesCount=History.Where(t=>t.ClosingTime.Date==Server.Time.Date).Count();if(todayTradesCount<MaxTradesPerDay)returnfalse;Print("Trial limit reached: maximum trades for today.");returntrue;}// Rest of your cBot logic}
1 2 3 4 5 6 7 8 910111213141516171819202122
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():MaxTradesPerDay=5defon_bar(self):ifself.is_max_daily_trade_reached():return# Skip trading logic if max trade number reacheddefis_max_daily_trade_reached(self):todayTradesCount=len([tfortinapi.Historyift.ClosingTime.Date==Server.Time.Date])iftodayTradesCount<self.MaxTradesPerDay:returnFalseprint(f"Trial limit reached: maximum trades for today.")returnTrue# Rest of your cBot logic
Operasi terbatas waktu
Kodekan cBot untuk mengirim tanggal mulai yang terkait dengan cTID pengguna saat dijalankan, dan konfigurasikan untuk berhenti berfungsi setelah periode tetap. Untuk mencegah pengguna melewati konfigurasi awal uji coba, pertimbangkan menggunakan layanan API jarak jauh atau solusi aman serupa.
1 2 3 4 5 6 7 8 910111213141516171819202122232425
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{privateconstintTrialDays=5;protectedoverridevoidOnStart(){// Do the same check on other methods like OnTick, OnBar, etc...if(Server.Time>=GetTrialStartTime().AddDays(TrialDays))OnTrialExpired();}privateDateTimeGetTrialStartTime(){// Add here the logic for getting trial start time from your secure remote service}privatevoidOnTrialExpired(){Print("Your trial period has expired. Please purchase the full version.");Stop();}// Rest of your cBot logic}
1 2 3 4 5 6 7 8 91011121314151617181920212223
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():TrialDays=5defon_start(self):# Do the same check on other methods like on_tick, on_bar, etc...ifapi.Server.Time>=self.get_trial_start_time().AddDays(self.TrialDays):self.on_trial_expired()defget_trial_start_time(self):# Add here the logic for getting trial start time from your secure remote servicepassdefon_trial_expired(self):print("Your trial period has expired. Please purchase the full version.")api.Stop()# Rest of your cBot logic
Batasan berbasis sesi
Izinkan cBot untuk trading hanya dalam satu sesi.
1 2 3 4 5 6 7 8 91011121314
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{protectedoverridevoidOnBar(){// Do the same check on other methods like OnTick, etc...if(!IsValidSession())return}privateboolIsValidSession()=>MarketSessions.HasFlag(MarketSession.London)// Rest of your cBot logic}
1 2 3 4 5 6 7 8 910111213141516
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():defon_bar(self):# Do the same check on other methods like on_tick, etc...ifself.is_valid_session()==False:returndefis_valid_session(self):returnapi.MarketSessions.HasFlag(MarketSession.London)# Rest of your cBot logic
Hanya trading simulasi
Kodekan cBot untuk mencatat di mana ia akan trading dan tidak menjalankan trading.
1 2 3 4 5 6 7 8 91011121314151617181920
[Robot(AccessRights = AccessRights.None)]publicclassTest:Robot{protectedoverridevoidOnBar(){// Example: simple signalvarbuySignal=Bars.ClosePrices.Last(1)>Bars.OpenPrices.Last(1);if(buySignal){// In full version, this is where you would execute an order:// ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);// In the trial: only log the virtual actionPrint($"[TRIAL] Would open BUY position at {Symbol.Ask}");}}// Rest of your cBot logic}
1 2 3 4 5 6 7 8 910111213141516171819
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():defon_bar(self):# Example: simple signalbuySignal=api.Bars.ClosePrices.Last(1)>api.Bars.OpenPrices.Last(1)ifbuySignal:# In full version, this is where you would execute an order:# api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000);# In the trial: only log the virtual actionprint(f"[TRIAL] Would open BUY position at {api.Symbol.Ask}")# Rest of your cBot logic
Indikator
Struktur kode dari indikator uji coba mungkin terlihat seperti ini:
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():definitialize(self):# Trial setup checks go herepassdefcalculate(self,index):# Trial indicator logic goes herepass
Fungsi yang dikurangi
Indikator uji coba menjalankan perhitungan dasar, sementara versi lengkapnya mengandung logika yang lebih canggih.
1 2 3 4 5 6 7 8 9101112131415161718
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]publicclassTest:Indicator{[Output("Result", LineColor = "DodgerBlue")]publicIndicatorDataSeriesResult{get;set;}protectedoverridevoidInitialize(){}publicoverridevoidCalculate(intindex){// Trial build: simplified logic onlyResult[index]=(Bars.HighPrices[index]+Bars.LowPrices[index])/2;// Full version might add more lines, buffers, filters, etc.}}
1 2 3 4 5 6 7 8 9101112131415
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():definitialize(self):passdefcalculate(self,index):# Trial build: simplified logic onlyapi.Result[index]=(api.Bars.HighPrices[index]+api.Bars.LowPrices[index])/2# Full version might add more lines, buffers, filters, etc.
Simbol dan timeframe yang dikodekan secara manual
Kodekan indikator untuk menampilkan output hanya ketika simbol dan timeframe tertentu digunakan.
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]publicclassTest:Indicator{[Output("Result", LineColor = "DodgerBlue")]publicIndicatorDataSeriesResult{get;set;}privateconststringValidSymbolName="EURUSD";privateconststringValidTimeFrame="Hour";protectedoverridevoidInitialize(){if(!IsSymbolAndTimeFrameValid()){Chart.DrawStaticText("symbolLimit","Trial version supports only EURUSD and GBPUSD.",VerticalAlignment.Center,HorizontalAlignment.Center,Color.Yellow);return;}}publicoverridevoidCalculate(intindex){if(!IsSymbolAndTimeFrameValid())return;// Rest of your indicator logic}privatevoidIsSymbolAndTimeFrameValid(){returnSymbolName==ValidSymbolName&&TimeFrame.Name==ValidTimeFrame;}}
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():ValidSymbolName="EURUSD"ValidTimeFrame="Hour"definitialize(self):ifself.is_symbol_and_time_frame_valid()==False:api.Chart.DrawStaticText("symbolLimit","Trial version supports only EURUSD and GBPUSD.",VerticalAlignment.Center,HorizontalAlignment.Center,Color.Yellow)returndefcalculate(self,index):ifself.is_symbol_and_time_frame_valid()==False:return# Rest of your indicator logicdefis_symbol_and_time_frame_valid(self):returnapi.SymbolName==self.ValidSymbolNameandapi.TimeFrame.Name==self.ValidTimeFrame
Operasi terbatas waktu
Kodekan indikator untuk berhenti menampilkan output setelah masa berlaku habis dan hanya menampilkan pesan.
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]publicclassTest:Indicator{[Output("Result", LineColor = "DodgerBlue")]publicIndicatorDataSeriesResult{get;set;}protectedoverridevoidInitialize(){}publicoverridevoidCalculate(intindex){if(IsTrialExpired()){Result[index]=double.NaN;return;}// Rest of your indicator logic}privateboolIsTrialExpired(){// Here you can check if trial is expired or not// You have to store trial start time somewhere secure outside// user reach and comapre it with Server.Time// You can also let user know trial is expired by showing// a text message on chart, ex:// Chart.DrawStaticText(// "trial_expired",// "Trial expired. Please purchase the full version.",// VerticalAlignment.Center,// HorizontalAlignment.Center,// Color.Red// );}}
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*importmathclassTest():definitialize(self):passdefcalculate(self,index):ifself.is_trial_expired():api.Result[index]=math.nanreturn# Rest of your indicator logicdefis_trial_expired(self):# Here you can check if trial is expired or not# You have to store trial start time somewhere secure outside# user reach and comapre it with api.Server.Time# You can also let user know trial is expired by showing# a text message on chart, ex:# api.Chart.DrawStaticText(# "trial_expired",# "Trial expired. Please purchase the full version.",# VerticalAlignment.Center,# HorizontalAlignment.Center,# Color.Red# )
Plugin
Struktur kode dari plugin uji coba mungkin terlihat seperti ini:
1 2 3 4 5 6 7 8 9101112
[Plugin(AccessRights = AccessRights.None)]publicclassTest:Plugin{protectedoverridevoidOnStart(){// Trial setup or logic here}protectedoverridevoidOnStop(){}}
1 2 3 4 5 6 7 8 910111213
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():defon_start(self):# Trial setup or logic herepassdefon_stop(self,index):pass
Fungsi yang dikurangi
Versi uji coba hanya mencakup fitur dasar, sedangkan versi lengkap menyediakan semuanya.
[Plugin(AccessRights = AccessRights.None)]publicclassTest:Plugin{protectedoverridevoidOnStart(){// Use same check inside your plugin other methodsif(IsTrialExpired())OnTrialExpired();// You can also run timer and keep checking trial expiryTimer.Start(100)}protectedoverridevoidOnTimer(){if(IsTrialExpired())OnTrialExpired();}privateDateTimeIsTrialExpired(){// Here you have to check if user trial period is expired// or not, for that you have to store the trial start time// somewhere secure outside user access and compare it with// Server.Time}privatevoidOnTrialExpired(){// Do whatever you want when trial is expired hereMessageBox.Show("Trial expired");}}
importclrclr.AddReference("cAlgo.API")# Import cAlgo API typesfromcAlgo.APIimport*# Import trading wrapper functionsfromrobot_wrapperimport*classTest():defon_start(self):# Use same check inside your plugin other methodsifself.is_trial_expired():self.on_trial_expired()# You can also run timer and keep checking trial expiryTimer.Start(100)defon_timer(self,index):ifself.is_trial_expired():self.on_trial_expired()defis_trial_expired(self):# Here you have to check if user trial period is expired# or not, for that you have to store the trial start time# somewhere secure outside user access and compare it with# Server.Timedefon_trial_expired(self):# Do whatever you want when the trial has expired hereapi.MessageBox.Show("Trial expired")