MetaTraderPy
Check-in [970c143bec]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Python 2.6 version backport.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | python26
Files: files | file ages | folders
SHA1:970c143bec2370204fd57f8e3f3bac403f7a9df1
User & Date: polymeris 2012-10-03 23:24:22
Context
2012-10-03
23:28
Python 2.7 support. Leaf check-in: 678b41c855 user: polymeris tags: python27
23:24
Python 2.6 version backport. Leaf check-in: 970c143bec user: polymeris tags: python26
18:57
First import to fossil. Leaf check-in: 535f405d9e user: polymeris tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added include/py26.mqh.























































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
//+------------------------------------------------------------------+
//|                                                         py26.mqh |
//|                                                     Bernd Kreuss |
//|                                             mailto:7ibt@arcor.de |
//|                                                                  |
//|                                                                  |
//|               Python Integration For Metatrader 4                |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Bernd Kreuss"
#property link      "mailto:7ibt@arcor.de"

#define STDOUT "__python.out.txt" // filename for stdout and stderr redirect

#import "py26.dll" // dll version 1.3.0.x (for Python 2.6.x)

/**
* Initialize the Python environmant. This will start a new
* thread which will initialize Python and enter a sleep() loop.
* Dont call this directly, call PyInit() instead. (see below)
*/
void PyInitialize();

/**
* Return True if PyInitialize() has already been called
*/
bool PyIsInitialized();

/**
* Decrease the reference counter of a Python object by one and free the
* object if the counter reaches zero. You may only call this for objects
* that you OWN yourself, not for BORROWED references.
*/
void PyDecRef(int p_object);

/**
* Increase the reference counter by one
*/
void PyIncRef(int p_object);

/**
* Execute an arbitrary piece of python code
*/
void PyExecute(string python_source);

/**
* Evaluate a python expression and return your NEW OWN
* reference to the result. For example if foo.bar.baz is a list
* and you want a reference to it so you can directy loop through
* its members then just call PyEvaluate("foo.bar.baz") and use 
* the return value as a handle for the PyLookupList() function.
* You can also use this handle for PyListAppend() because it is
* *not* a copy but rather a reference to the original list.
* 
* After you are done with using the handle returned by PyEvaluate()
* you MUST call PyDecRef() to signal Python that you are now done 
* with this object, this will restore the reference counter to
* the value it had before or free it completely if the object
* was created by the code you evaled (return value of a function 
* or the result of a calculation which python will no longer 
* need after you read it)
*/
int PyEvaluate(string python_source); // new reference, PyDecRef() after using!

/**
* return a BORROWED reference to the __main__ dict
*/
int PyMainDict();

/**
* return a BORROWED reference to the item in the dict
* specified by name.
*/
int PyLookupDict(int p_dict, string name);

/**
* return a BORROWED reference to the item in the list
* specified by index.
*/
int PyLookupList(int p_list, int index);

/**
* return the value of the object as int
* (if it is a numeric object)
*/
int PyGetInt(int ptr_int);

/**
* return the value of the object as a double
* (if it is a numeric object)
*/
double PyGetDouble(int p_double);

/**
* return the value of the object as a string
* (only if it actually is a string object)
*/
string PyGetString(int p_string);

/**
* create a new integer obect. You will OWN a reference, 
* so take care of the reference counter
*/  
int PyNewInt(int value);

/**
* create a new double (actually a python float) object. 
* You will OWN a reference, so take care of the reference counter
*/  
int PyNewDouble(double value);

/**
* create a new string obect. You will OWN a reference, 
* so take care of the reference counter
*/  
int PyNewString(string value);

/**
* append the item to the list. This function will NOT steal
* the reference, it will create its own, so ownership
* will not change, so if it was your OWN and NOT a
* borrowed reference you must decref after you are done
*/
void PyListAppend(int p_list, int p_item);

/**
* return the size of the list object
*/
int PyListSize(int p_list);

#import

/**
* below are some higher level abstractions, here you dont have to
* care about reference counting when using the functions, you will
* not be exposed to handles of python objects
*/


/**
* initialize the Python environment. This should be called
* from your init() function. It is safe to call it a second
* time, subsequent calls will just be ignored.
*/
void PyInit(){
   if (!PyIsInitialized()){
      PyInitialize();
      PyExecute("import os, sys");
      PyExecute("os.chdir(\"" + TerminalPath() + "/experts\")");
      PyExecute("sys.path.insert(0, os.getcwd())");
      
      // redirect stdout and stderr
      PyExecute("__outfile__ = open(\"" + STDOUT + "\", \"w\", 0)");
      PyExecute("sys.stdout = __outfile__");
      PyExecute("sys.stderr = __outfile__");
      PyExecute("print \"Python \" + sys.version");
      PyExecute("print \"output of stdout and stderr:\"");
   }
   PyOutEmpty();
}

/**
* empty the stdout file (where the redirected print output and errors go)
*/
void PyOutEmpty(){
   PyExecute("__outfile__.seek(0, os.SEEK_SET)");
   PyExecute("__outfile__.truncate(0)");
   PyExecute("print \"Python \" + sys.version");
   PyExecute("print \"output of stdout and stderr:\"");
}

/**
* Evaluate a python expression that will evaluate to an integer 
* and return its value
*/
int PyEvalInt(string python_source){
   int p_res = PyEvaluate(python_source);
   int res = PyGetInt(p_res);
   PyDecRef(p_res);
   return(res);
}

/**
* Evaluate a python expression that will evaluate to a double 
* and return its value
*/
double PyEvalDouble(string python_source){
   int p_res = PyEvaluate(python_source);
   double res = PyGetDouble(p_res);
   PyDecRef(p_res);
   return(res);
}

/**
* Evaluate a python expression that will evaluate to a string 
* and return its value
*/
string PyEvalString(string python_source){
   int p_res = PyEvaluate(python_source);
   string res = PyGetString(p_res);
   PyDecRef(p_res);
   return(res);
}

/**
* append the array of int to the python list given by its name.
* the list must already exist. The same could be achieved
* by putting PyExecute() calls with generated python code
* into a loop but this would invoke parser and compiler for
* every new list item, directly accessing the python objects
* like it is done here is far more effective.
*/
int PyListAppendInt(string list_name, int array[]){
   int list,item,len,i;
   list = PyEvaluate(list_name);
   len = ArraySize(array);
   for (i=0; i<len; i++){
      item = PyNewInt(array[i]);
      PyListAppend(list, item);
      PyDecRef(item);
   }
   len = PyListSize(list);
   PyDecRef(list);
   return(len);
}

/**
* append the array of double to the python list given by its name.
* the list must already exist.
*/
int PyListAppendDouble(string list_name, double array[]){
   int list,item,len,i;
   list = PyEvaluate(list_name);
   len = ArraySize(array);
   for (i=0; i<len; i++){
      item = PyNewDouble(array[i]);
      PyListAppend(list, item);
      PyDecRef(item);
   }
   len = PyListSize(list);
   PyDecRef(list);
   return(len);
}

/**
* append the array of string to the python list given by its name.
* the list must already exist.
*/
int PyListAppendString(string list_name, string array[]){
   int list,item,len,i;
   list = PyEvaluate(list_name);
   len = ArraySize(array);
   for (i=0; i<len; i++){
      item = PyNewString(array[i]);
      PyListAppend(list, item);
      PyDecRef(item);
   }
   len = PyListSize(list);
   PyDecRef(list);
   return(len);
}



/* Some words:
 *************


* One Interpreter 
  ===============

  All expert advisors and indicators share the same 
Python interpreter with the same global namespace, so you should 
separate them by encapsulating all in classes and instantiate and 
store them with all their state in variables named after the symbol 
(or maybe even symbol + timeframe).


* Init 
  ====
  
  Put your Python classes into Python modules, the import path 
is <metatrader>\experts, the same folder where your EA's mql code 
is located, so a simple PyExecute("import yourmodule"); in your 
init() will import the file yourmodule.py from this folder. Then 
instantiate an instance of your main class with something like 
PyExecute(Symbol() + Period() + " = yourmodule.yourclass()"); 
This way each instance of your EA can keep track of its own 
Python counterpart by accessing it via this global variable.

  Your init() function may look similar to this:
  
int init(){
   // initialize Python
   PyInit();
   
   // import my module
   PyExecute("import mymodule");
   
   // instantiate some objects 
   PyExecute("myFoo_" + Symbol() + Period() + " = mymodule.Foo()");
   PyExecute("myBar_" + Symbol() + Period() + " = mymodule.Bar()");
   
   return(0);
}


* Deinit 
  ======
  
  Use the deinit() function of the EA or Indicator to destroy 
these instances, be sure to terminate all threads they may have 
started, make sure you can terminate them fast within less than a 
second because Metatrader has a timeout here, wait inside python 
in a tight loop with time.sleep() until they are terminated before 
returning to prevent Metatrader from proceding with its deinit
while your threads are stll not all ended!

  Your deinit() function may look like this:
  
int deinit(){
   // tell my objects they should commit suicide by
   // calling their self destruction method
   PyExecute("myFoo_" + Symbol() + Period() + ".stopAndDestroy()");
   PyExecute("myBar_" + Symbol() + Period() + ".stopAndDestroy()");
   
   return(0);
}


* Global unload hook
  ==================
  
  If the last EA that used Python has been removed the Python 
interpreter itself will be terminated and unloaded. 
  
  You can register cleanup functions (do it per imported module, not 
per instance!) with the atexit module, it will be called after the 
last EA's deinit(), again as above make it wait for all cleaning 
action to be finished before returning, these are the last clock 
cycles that will be spent inside Python because at this time there 
is only one system thread left and if this function returns the 
python interpreter will be frozen and then immediately unloaded.

*/


Changes to include/python.mqh.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// Wrapper around Bernd Kreuss' python integration.
/// Handles common data exchange issues.
/// Read the comments in metatrader.py for more information.

#property copyright "Camilo Polymeris"
#property link      "http://www.udec.cl/~cpolymeris/MetaTraderPy/"

#include <py27.mqh>
#include <WinUser32.mqh>

/// The adivisor's unique python variable name
string adv;
/// Temporary storage for python commands
string py;
/// Temporrary storage for python values.







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// Wrapper around Bernd Kreuss' python integration.
/// Handles common data exchange issues.
/// Read the comments in metatrader.py for more information.

#property copyright "Camilo Polymeris"
#property link      "http://www.udec.cl/~cpolymeris/MetaTraderPy/"

#include <py26.mqh>
#include <WinUser32.mqh>

/// The adivisor's unique python variable name
string adv;
/// Temporary storage for python commands
string py;
/// Temporrary storage for python values.

Added libraries/py26.dll.

cannot compute difference between binary files