There are still a lot of bugs
//+------------------------------------------------------------------+ //| eaPermanentPortfolio.mq5 | //| Copyright 2018, Pierre Rougier | //| http://www.apprendre-mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, Pierre Rougier" #property link "http://www.apprendre-mql5.com" #property version "1.00" #include <Trade\Trade.mqh> CTrade myTradingControlPanel; input int capital_dedicated_to_strategy=10000; input string stocks= "VTI"; input string bonds ="TLTUS"; input string cash = "SHY"; input string gold = "GLD"; input int magicNumber=12345; int year_saved=0; bool is_trades_already_open=false; double total_current_value=0; double target_value=0; double current_value_stocks= 0; double current_value_bonds = 0; double current_value_cash = 0; double current_value_gold = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- MqlDateTime mql_datetime; TimeToStruct(iTime(_Symbol,_Period,0),mql_datetime); year_saved=mql_datetime.year; //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- if(isNewYear()) { if(!is_trades_already_open) {StartStrategy();} else {RebalanceAllAssetsClass();} } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool isNewYear() { MqlDateTime mql_datetime; TimeToStruct(iTime(_Symbol,_Period,0),mql_datetime); if(mql_datetime.year!=year_saved) { year_saved=mql_datetime.year; return true; } else {return false;} } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void StartStrategy() { target_value=capital_dedicated_to_strategy/4; Print("/*§§*/ total_current_value :"+DoubleToString(total_current_value)); Print("/*§§*/ target_value :"+DoubleToString(target_value)); Rebalance(stocks,0); Rebalance(bonds,0); Rebalance(cash,0); Rebalance(gold,0); is_trades_already_open=true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void RebalanceAllAssetsClass() { ComputeValuePositionsByAssetsClass(); total_current_value=current_value_stocks+current_value_bonds+current_value_cash+current_value_gold; target_value=total_current_value/4; Print("/*§§*/ total_current_value :"+DoubleToString(total_current_value)); Print("/*§§*/ target_value :"+DoubleToString(target_value)); Rebalance(stocks,current_value_stocks); Rebalance(bonds,current_value_bonds); Rebalance(cash,current_value_cash); Rebalance(gold,current_value_gold); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Rebalance(string asset_class_type,double current_value_asset) { double amount=0; int quantity=0; double ask=SymbolInfoDouble(asset_class_type,SYMBOL_ASK); if(current_value_asset>target_value) { amount=current_value_asset-target_value; quantity=(int)NormalizeDouble((amount/ask),0); if(quantity>0) { SellSurplusAssetClass(asset_class_type,quantity); } } else { amount=target_value-current_value_asset; quantity=(int)NormalizeDouble((amount/ask),0); if(quantity>0) { BuyMissingPartAssetClass(asset_class_type,quantity); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void BuyMissingPartAssetClass(string asset_class_type,int quantity) { // Open a Buy (i.e. long) position myTradingControlPanel.PositionOpen(asset_class_type,ORDER_TYPE_BUY,quantity, 0, // SymbolInfoDouble(asset_class_type,SYMBOL_ASK), 0,0,"Buy Trade. Magic Number #" +(string) myTradingControlPanel.RequestMagic()); // Request is completed or order placed if(myTradingControlPanel.ResultRetcode()==TRADE_RETCODE_PLACED || myTradingControlPanel.ResultRetcode()==TRADE_RETCODE_DONE) { Print("Entry rules: A ",asset_class_type," Buy order has been successfully placed with Ticket#: ",myTradingControlPanel.ResultOrder()); } else { Print("Entry rules: A ",asset_class_type," Buy order request could not be completed. Error: ",GetLastError()); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void SellSurplusAssetClass(string asset_class_type,int quantity) { // Close position myTradingControlPanel.PositionOpen(asset_class_type,ORDER_TYPE_SELL,quantity, 0, // SymbolInfoDouble(asset_class_type,SYMBOL_ASK), 0,0,"Sell Trade. Magic Number #" +(string) myTradingControlPanel.RequestMagic()); // Request is completed or order placed if(myTradingControlPanel.ResultRetcode()==TRADE_RETCODE_PLACED || myTradingControlPanel.ResultRetcode()==TRADE_RETCODE_DONE) { Print("Entry rules: A ",asset_class_type," Sell order has been successfully placed with Ticket#: ",myTradingControlPanel.ResultOrder()); } else { Print("Entry rules: A ",asset_class_type," Sell order request could not be completed. Error: ",GetLastError()); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void ComputeValuePositionsByAssetsClass() { // Loop through all open positions for(int i=PositionsTotal()-1; i>=0; i--) { ulong ticketNumber=0; // This selects open position by the order they appear in our list of positions ticketNumber=PositionGetTicket(i); if(ticketNumber==0) { Print("Exit rules: Position exists but not selected. Error: ",GetLastError()); ResetLastError(); continue; } if(PositionGetInteger(POSITION_MAGIC)==magicNumber) { string symbol=PositionGetString(POSITION_SYMBOL); if(symbol==stocks) { current_value_stocks=current_value_stocks+PositionGetDouble(POSITION_PRICE_CURRENT); } else if(symbol==bonds) { current_value_bonds=current_value_bonds+PositionGetDouble(POSITION_PRICE_CURRENT); } else if(symbol==cash) { current_value_cash=current_value_cash+PositionGetDouble(POSITION_PRICE_CURRENT); } else if(symbol==gold) { current_value_gold=current_value_gold+PositionGetDouble(POSITION_PRICE_CURRENT); } } } }; //+------------------------------------------------------------------+
Hello,
This will allow me to test it with ETFs.
https://www.metaquotes.net/en/company/news/5123
I have just started, there are many mistakes.
If you wish to participate, you are welcome to post an improved version in a new message.