OK - I'll try to help and jump start you as much as time permits.
I originally got interested in your post as a vector "challenge", but quickly realized that you were in the 5% that I referred to that needs a DLL to "just get it done".
I will post some AFL code below that slightly restructures your original code as a function to make the DLL easier to see. The DLL call is commented out so that it executes just the AFL function. You will want to add exploration output as you did before to test results.
You didn't indicate if you are familiar with VC++ or an alternative, but let's assume that and jump in. As an intraday user, this need will probably come up again. If you are not familiar, then take Beppe's suggestion, as VC++ is a PITA to learn.
Just get the Sample sub-dir from the Samples directory at the link that Beppe gave you. You will be replacing the Functions.cpp file.
But, first there are a couple of subleties to be aware of for the DLL to keep it as simple as possible -
- As you can see from the SwingTouchDetect() call in the code, I've kept a strict order (arrays, then scalar) to keep it simple.
- The 4 "output" vectors are passed as call by reference parameters (with "&") and are pre-allocated in the AFL. The DLL overwrites them. BTW this makes the DLL simpler since it doesnt' have to do any array allocations, set variables, etc.
- The 4 output vectors must be initialized as arrays since auto-promotion from scalars is not done in the DLL. For an array of -1's this is done as "C - C - 1", for example.
In the DLL, which you should do, there are a couple of things to point out -
- The code from the AFLSwingTouchDetect() function plugs in ALMOST AS IS with a minor change of the "AND" to "&&".
- The function table at the end of Functions.cpp looks like this -
FunctionTag gFunctionTable[] = {
"SwingTouchDetect", { VSwingTouchDetect, 8, 0, 1, 0, NULL },
- Parameters are retrieved as in this example for the first few -
float* H = ArgsTable[0].array;
float* L = ArgsTable[1].array;
float* SwingHighPrice = ArgsTable[2].array;
There are many more details that could be covered, but this should get you going, and I'm at a time stop. Come back if you hit a road block.
================
Here's the AFL -
SwingSize = Param("Swing : Size (Bars/Ticks)", 3, 1, 1000, 1);
SwingWindow = 2 * SwingSize + 1;
SwingHighCandidate = Ref(H, -SwingSize);
SwingLowCandidate = Ref(L, -SwingSize);
SwingHighPrice = IIf(HHV(H, SwingWindow) == SwingHighCandidate, SwingHighCandidate, -1);
SwingLowPrice = IIf(LLV(L, SwingWindow) == SwingLowCandidate, SwingLowCandidate, -1);
////// Swing touched detection //////
// This is the slow part that I want to convert into AFL logic
CleanSwingHighTouched = 0;
CleanSwingLowTouched = 0;
CleanSwingHighTouchedIndex = -1;
CleanSwingLowTouchedIndex = -1;
AFLDetect = True;
DLLDetect = True;
_TRACE( " " );
//--------------------------------------------------------------------------------------------------
// Function to detect swing touches using AFL looping -
// Will be SLOW - even with first touch break
//--------------------------------------------------------------------------------------------------
function AFLSwingTouchDetect( H, L, SwingHighPrice, SwingLowPrice,
CleanSwingHighTouched2, CleanSwingLowTouched2,
CleanSwingHighTouchedIndex2, CleanSwingLowTouchedIndex2,
BarCount )
{
for (i = 0; i < Barcount; i++) {
// Swing high
if (SwingHighPrice[i] >= 0) {
// Look forward for the first bar that touches this level
for (j = i + 1; j < BarCount; ++j) {
if (H[j] >= SwingHighPrice[i] AND L[j] <= SwingHighPrice[i]) {
// Mark touch price on that bar
CleanSwingHighTouched[j] = SwingHighPrice[i];
// Store at swing bar the index of the bar that will touch it
CleanSwingHighTouchedIndex[i] = j;
break; // only first touch counts
}
}
}
// Same for swing low
if (SwingLowPrice[i] >= 0) {
for (j = i + 1; j < BarCount; ++j) {
if (H[j] >= SwingLowPrice[i] AND L[j] <= SwingLowPrice[i]) {
CleanSwingLowTouched[j] = SwingLowPrice[i];
CleanSwingLowTouchedIndex[i] = j;
break;
}
}
}
}
return;
}
//--------------------------------------------------------------------------------------------------
if ( AFLDetect ) {
GetPerformanceCounter( True );
// Order of parms is done to match DLL implementation - see DLL call comments
AFLSwingTouchDetect( H, L, SwingHighPrice, SwingLowPrice,
&CleanSwingHighTouched, &CleanSwingLowTouched,
&CleanSwingHighTouchedIndex, &CleanSwingLowTouchedIndex,
BarCount );
elapsed1 = GetPerformanceCounter();
_TRACE( "elapsed1 = " + elapsed1 );
}
if ( DLLDetect ) {
//************************************************
// Make sure they are arrays before passing by reference -
// otherwise they won't be promoted if scalar
//************************************************
CleanSwingHighTouched2 = C - C + 0;
CleanSwingLowTouched2 = C - C + 0;
CleanSwingHighTouchedIndex2 = C - C - 1;
CleanSwingLowTouchedIndex2 = C - C - 1;
GetPerformanceCounter( True );
// Small hacks can be used to change order - but conform to strict DLL rules
/*
res = SwingTouchDetect( H, L, SwingHighPrice, SwingLowPrice, // Input arrays
&CleanSwingHighTouched2, &CleanSwingLowTouched2, // Output arrays
&CleanSwingHighTouchedIndex2, &CleanSwingLowTouchedIndex2,
BarCount ); // Input scalar
*/
elapsed2 = GetPerformanceCounter();
_TRACE( "elapsed2 = " + elapsed2 );
}```