Practice

Recommendations for the practice of using the ATcl library

The latest version of the library can always be downloaded by following the instructions on the install page

To find out which version of the ATcl library and Tcl you can use a simple script:

#include <ATcl\\ATcl.mqh>
 
void OnStart()
{
  PrintFormat("ATcl version: %s",ATcl_Version());
  ATcl_OnInit();
  ATcl *tcl=new ATcl;
  if (tcl!=NULL && tcl.Ready()) {
    PrintFormat("Tcl version: %f",tcl.DoubleEval("info tclversion"));
    PrintFormat("Tcl pathLevel: %s",tcl.StringEval("set tcl_patchLevel"));
    PrintFormat("Tcl library: %s",tcl.StringEval("info library"));
    PrintFormat("    auto_path: %s",tcl.StringEval("set auto_path"));
    Tcl_Obj names=tcl.Ref(tcl.ObjEval("array names tcl_platform"));
    Tcl_Obj tcl_platform=tcl.Ref(tcl.Obj("tcl_platform"));
    int total=tcl.Count(names);
    for(int t=0;t<total;t++) {
      Tcl_Obj key=tcl.ObjIndex(names,t);
      PrintFormat("   tcl_platform(%s):%s",tcl.String(key),tcl.String(tcl.Get(tcl_platform,key)) );
    }
    tcl.Unref(tcl_platform);
    tcl.Unref(names);
  }
  delete tcl;
  ATcl_OnDeinit();
}

full version of the script is included in the ATcl MQL4 / Scripts / ATcl / version.mq4 distribution

MQL as the base language of the trading platform is quite good in terms of convenience and speed of calculations. Simply supplement it with Tcl capabilities - integrate your Indicators and Experts with DBMS, system, network services and other applications using Tcl packages.

Place your scripts as you feel comfortable. You can store them in one system catalog and use them from several instances of MetaTrader and other projects. I prefer to keep scripts with c: \ forex \ tcl.

#include <ATcl\\ATcl.mqh>
ATcl *tcl;
int ReadScripts(ATcl *tcl) {
  if (tcl==NULL || !tcl.Ready()) {
    return TCL_ERROR;
  }
  tcl.Eval("source c:/forex/tcl/script.tcl"); 	// load all the necessary scripts
  tcl.Eval("source c:/forex/tcl/script2.tcl"); 	// you can use / as well as \\ as the path separator
}
void OnStart() {
  ATcl_OnInit();
  tcl=new ATcl;
  ReadScripts(tcl);	// load the necessary scripts into the interpreter
  ...
  ATcl_OnDeinit();
}

A good idea is also the organization of scripts in tcl packages and the use of autoloading commands and packages

Although tcl functions can be called from anywhere in the program using the Call and Eval methods, the best solution is to do interface functions and classes that hide the mechanics of working with the interpreter.

#include <ATcl\\ATcl.mqh>
ATcl *tcl=0;
Tcl_Obj localMscProc=0;
// LocalMsc (); current system time accurate to milliseconds
// otherwise MQL code use this function instead of tcl.LongCall (localMscProc)
long LocalMsc() {
  return tcl.LongCall(localMscProc);	  
}
 
void OnStart() {
  ATcl_Init();
  tcl=new ATcl;
  localMscProc=tcl.Ref(tcl.Obj("localMsc"));
  tcl.Eval("proc localMsc {} { clock clicks -milliseconds }");
  ...
  tcl.Unref(localMscProc);  
  ATcl_OnDeinit();
}

Like MQL, Tcl provides all the possibilities for object-oriented programming. Both at the level of the base language OO, and at the expense of its extensions itcl, XOtcl, Next-Scripting

An example of using the elementary class tcl in the MQL class:

Stack.tcl
#!/usr/bin/tclsh
oo::class create Stack {
	variable data
	constructor {} {
		set data {}
	}
	destructor {
	}
	method Push { value } {
		lappend data $value
	}
	method Pop {} {
		set value [ lindex $data end ]
		set data [ lrange $data 0 end-1 ]
		return $value
	}
	export Push Pop
}
oostack.mq4
#include <ATcl\\ATcl.mqh>
ATcl *tcl;
 
class Stack {
protected:
   Tcl_Obj obj;
public:
   Stack() {
      obj=tcl.ObjEval("Stack new");
      tcl.Ref(obj);
   }
   ~Stack() {
      tcl.Call(obj,tcl.Obj("destroy"));
      tcl.Unref(obj);
   }
   void Push(string s) {
      tcl.Call(obj,tcl.Obj("Push"),tcl.Obj(s));
   }
   string Pop() {
      return tcl.StringCall(obj,tcl.Obj("Pop"));
   }
};
 
void OnStart()
{
   ATcl_OnInit();
   tcl=new ATcl;
   if (tcl!=NULL && tcl.Ready()) {
      if (tcl.Eval("source MQL4/Files/ATcl/Stack.tcl")!=TCL_OK) {
         PrintFormat("Error: %s",tcl.StringResult());
      } else {
         Stack stack;
         stack.Push("hello");
         stack.Push("word");
         PrintFormat("pop: %s",stack.Pop());
         PrintFormat("pop: %s",stack.Pop());
      }
   }
   delete tcl;
   ATcl_OnDeinit();
}

Tcl provides the library tcltest used in many software testing systems. Use it to build a test system for your scripts.