I'm coding an Indicator which calls a function from C++ DLL. I need to pass only Close rates to DLL and return a string from DLL.
MQL4 code:
#import "PythonZones.dll"
void CalculateZones(double &data[], double quantile, int arraySize,char&[]);
#import
#property indicator_chart_window
char buffer[4096];
input color M5color = clrTurquoise;
input int WINDOW = 446;
input double PARAM_SHIFT = 0.14;
int start()
{
if (IsNewBar()){
double data[];
ArrayResize(data,WINDOW);
Rate(data,WINDOW);
Print(data[0]);
CalculateZones(data,PARAM_SHIFT ,WINDOW,buffer);
string zones = CharArrayToString(buffer);
Print(zones);
}
return(0);
}
void Rate(double &out[],int len){
for(int i=(len - 1);i>-1;i--){
double close = iClose(NULL,0,i+1);
out[i] = close;
}
}
and C++ DLL code:
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
//#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <windows.h>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include "Python.h"
#include "numpy/arrayobject.h"
//----
#define MT4_EXPFUNC __declspec(dllexport)
PyObject *Amanda;
PyObject *AmandaZones;
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
//----
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Py_Initialize();
import_array1(-1);
PyObject *pName;
pName = PyString_FromString("Amanda");
Amanda = PyImport_Import(pName);
Py_DECREF(pName);
if (Amanda != NULL){
AmandaZones = PyObject_GetAttrString(Amanda, "CalculateZones");
if (AmandaZones == NULL){
OutputDebugString("Failed to get desired func.");
}
}else{
OutputDebugString("Failed to load Amanda.");
}
OutputDebugString("Attached.");
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Py_DECREF(Amanda);
Py_DECREF(AmandaZones);
Py_Finalize();
break;
}
//----
return(TRUE);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MT4_EXPFUNC void __stdcall CalculateZones(double *data, double quantile, int arraySize,char *buffer)
{
if (arraySize < 0) return;
npy_intp npy_arraysize;
npy_arraysize = arraySize;
PyObject *q = PyFloat_FromDouble(quantile);
PyObject *np_value = PyArray_SimpleNewFromData(1, &npy_arraysize, NPY_DOUBLE, data);
Py_INCREF(np_value);;
Py_INCREF(q);;
PyObject *pArgs = PyTuple_New(2);
PyTuple_SetItem(pArgs, 0, np_value);
PyTuple_SetItem(pArgs, 1, q);
PyObject *pResult = PyObject_CallObject(AmandaZones, pArgs);
Py_DECREF(pArgs);
Py_DECREF(np_value);
Py_DECREF(q);
char* res = PyString_AsString(pResult);
Py_DECREF(pResult);
strcpy(buffer,res);
}
Indicator works perfectly, but when I remove the indicator from the chart and add it again, It doesn't work anymore and returns an error "Access violation read" .
And also when I use it with Strategy Tester, MetaTrader crashes without logging any error.
I think the problem is with the array referencing. I attempted to try it with using struct
instead of arrays, but I couldn't compile it any way because I don't know MQL4 or C++ well.
How can I solve the problem?