Repository navigation
Expand file tree
/
Copy pathDanDeltaWizWorkerSlave.cpp
More file actions
388 lines (298 loc) · 14.8 KB
/
Copy pathDanDeltaWizWorkerSlave.cpp
File metadata and controls
388 lines (298 loc) · 14.8 KB
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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
#include "sierrachart.h"
#include "common.h"
#include <cmath>
void displayBadge(SCStudyInterfaceRef sc, bool displayNoStopFoundError = false) {
s_UseTool sessionStatusText;
int activated = sc.GetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATED);
sessionStatusText.Clear();
sessionStatusText.ChartNumber = sc.ChartNumber;
sessionStatusText.Region = sc.GraphRegion;
sessionStatusText.DrawingType = DRAWING_TEXT;
sessionStatusText.TextAlignment = DT_LEFT;
sessionStatusText.FontSize = 10;
sessionStatusText.UseRelativeVerticalValues = 1;
sessionStatusText.ReverseTextColor = 0;
sessionStatusText.LineNumber = 3717;
sessionStatusText.AddMethod = UTAM_ADD_OR_ADJUST;
// vertical position .... 100 = top
sessionStatusText.BeginValue = 94;
// horizontal position ... 0-150
sessionStatusText.BeginDateTime = 2;
sessionStatusText.Text.Format("WorkerSlave: %s", activated == 1 ? "ACTIVE" : "INACTIVE");
sessionStatusText.Color = activated == 1 ? RGB(0, 255, 0) : RGB(255, 0, 0);
sessionStatusText.FontBold = true;
sc.UseTool(sessionStatusText);
}
void displayNoStopErrorMessage(SCStudyInterfaceRef sc) {
s_UseTool sessionStatusText;
sessionStatusText.Clear();
sessionStatusText.ChartNumber = sc.ChartNumber;
sessionStatusText.Region = sc.GraphRegion;
sessionStatusText.DrawingType = DRAWING_TEXT;
sessionStatusText.TextAlignment = DT_LEFT;
sessionStatusText.FontSize = 10;
sessionStatusText.UseRelativeVerticalValues = 1;
sessionStatusText.ReverseTextColor = 0;
sessionStatusText.LineNumber = 3217;
sessionStatusText.AddMethod = UTAM_ADD_OR_ADJUST;
// vertical position .... 100 = top
sessionStatusText.BeginValue = 92;
// horizontal position ... 0-150
sessionStatusText.BeginDateTime = 2;
sessionStatusText.Text = "!! ERROR: No attached stop order found !!";
sessionStatusText.Color = RGB(255, 0, 0);
sessionStatusText.FontBold = true;
sc.UseTool(sessionStatusText);
}
void eraseNoStopErrorMessage(SCStudyInterfaceRef sc) {
sc.DeleteACSChartDrawing(sc.ChartNumber, TOOL_DELETE_CHARTDRAWING, 3217);
}
int getCurrentStopOrderId(SCStudyInterfaceRef sc) {
int Index = 0;
s_SCTradeOrder OrderDetails;
while (sc.GetOrderByIndex(Index, OrderDetails) != SCTRADING_ORDER_ERROR)
{
Index++; // Increment the index for the next call to sc.GetOrderByIndex
if (OrderDetails.OrderStatusCode != SCT_OSC_OPEN)
continue;
if (OrderDetails.ParentInternalOrderID == 0)//This means this is an Attached Order
continue;
if (OrderDetails.OrderTypeAsInt != SCT_ORDERTYPE_STOP)
continue;
//Get the internal order ID for the attached stop
int InternalOrderID = OrderDetails.InternalOrderID;
return InternalOrderID;
}
return 0;
}
void adjustStopPriceTo(SCStudyInterfaceRef sc, int orderId, float newStopPrice, int tradingDirection) {
SCInputRef Input_AllowAdjustmentToSmallerStops = sc.Input[4];
SCString MessageText;
// first run? allow smaller stops (from 30 to initial), even if the setting forbids it
int jungfrau = sc.GetPersistentInt(WORKERSLAVE_PERSISTENT_JUNGFRAUENMODUS);
// get current stop price
s_SCTradeOrder currentOrder;
sc.GetOrderByOrderID(orderId, currentOrder);
float currentStop = currentOrder.Price1;
bool doTheModification = false;
if (tradingDirection == ORDER_TYPE_BUY ? (newStopPrice < currentStop) : (newStopPrice > currentStop)) {
// new stop is larger than the existing stop ... this is always fine
doTheModification = true;
}
else if (Input_AllowAdjustmentToSmallerStops.GetBoolean()) {
// new stop is lower or equal, only allow if smaller stops are ok
doTheModification = true;
}
else if ((!Input_AllowAdjustmentToSmallerStops.GetBoolean()) && (jungfrau == 1)) {
// // if smaller stops are NOT ok but this is the first time, still allow the smaller stop so that we can move away from the notstop
doTheModification = true;
}
MessageText.Format("!! Stop-modification decision based on settings/parameters is: %i", doTheModification);
sc.AddMessageToLog(MessageText, 0);
if (doTheModification) {
s_SCNewOrder ModifyOrder;
ModifyOrder.InternalOrderID = orderId;
ModifyOrder.Price1 = newStopPrice;
sc.ModifyOrder(ModifyOrder);
// stop gezogen, jungfrau ist futsch
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_JUNGFRAUENMODUS, 0);
}
}
bool isActivated(SCStudyInterfaceRef sc) {
return (sc.GetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATED) > 0);
}
/*==========================================================================*/
SCSFExport scsf_DeltaWizWorkerSlave(SCStudyInterfaceRef sc)
{
SCInputRef Input_Enabled = sc.Input[0];
SCInputRef Input_AdjustOffset = sc.Input[1];
SCInputRef Input_AutoDeactivateStudyAfterLeavingZone = sc.Input[2];
SCInputRef Input_StudyDeactivationOffset = sc.Input[3];
SCInputRef Input_AllowAdjustmentToSmallerStops = sc.Input[4];
SCString MessageText;
if (sc.SetDefaults)
{
sc.GraphName = "DeltaWiz WorkerSlave";
sc.AutoLoop = 0;//Auto looping
sc.GraphRegion = 0;
sc.ScaleRangeType = SCALE_SAMEASREGION;
Input_Enabled.Name = "DeltaWiz WorkerSlave Enabled";
Input_Enabled.SetYesNo(true);
Input_AdjustOffset.Name = "Stop Adjust Offset";
Input_AdjustOffset.SetInt(4);
Input_AdjustOffset.SetIntLimits(1, 1000);
Input_AdjustOffset.SetDescription("Number of Ticks to offset the newly adjusted Stop.");
Input_AutoDeactivateStudyAfterLeavingZone.Name = "Auto deactivate Study after Leaving Zone";
Input_AutoDeactivateStudyAfterLeavingZone.SetYesNo(false);
Input_AutoDeactivateStudyAfterLeavingZone.SetDescription("If activated, the study deactivates after closing price above x ticks and then moves the stop below the zone.");
Input_StudyDeactivationOffset.Name = "Study Deactivation Offset";
Input_StudyDeactivationOffset.SetInt(10);
Input_StudyDeactivationOffset.SetIntLimits(1, 1000);
Input_StudyDeactivationOffset.SetDescription("Number of Ticks above/below Zone where to Auto Deactivate Study.");
Input_AllowAdjustmentToSmallerStops.Name = "Allow Adjusted Stops to Get Smaller";
Input_AllowAdjustmentToSmallerStops.SetYesNo(false);
Input_AllowAdjustmentToSmallerStops.SetDescription("Do we allow that stops can get smaller or only bigger?");
sc.ReceivePointerEvents = false;
// During development set this flag to 1, so the DLL can be rebuilt without restarting Sierra Chart. When development is completed, set it to 0 to improve performance.
// sc.FreeDLL = 1;
sc.AllowMultipleEntriesInSameDirection = 1;
sc.AllowOppositeEntryWithOpposingPositionOrOrders = 1;
sc.CancelAllOrdersOnEntriesAndReversals = 0;
sc.AllowOnlyOneTradePerBar = 0;
sc.SupportReversals = 0;
sc.AllowEntryWithWorkingOrders = 1;
sc.SupportAttachedOrdersForTrading = 0;
sc.UseGUIAttachedOrderSetting = 1;
//use a high-value to effectively not put any Position Quantity restrictions
sc.MaximumPositionAllowed = 100000000;
return;
}
if (sc.IsUserAllowedForSCDLLName == false)
{
if (sc.Index == 0)
{
sc.AddMessageToLog("You are not allowed to use this study", 1);
}
return;
}
if (sc.LastCallToFunction)
{
// abriss
return;
}
if (sc.HideStudy)
return;
//For safety must never do any order management while historical data is being downloaded.
if (sc.ChartIsDownloadingHistoricalData(sc.ChartNumber))
return;
int index = sc.Index;
if (sc.UpdateStartIndex == 0)//Perform initialization
{
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATED, 0);
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATE_POST_ZONE_ADJUSTMENT, 0);
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_JUNGFRAUENMODUS, 1);
return;
}
// main update, done after the next bar is finished
if (index == 0) {
return;
}
displayBadge(sc);
sc.SetCustomStudyControlBarButtonHoverText(ACS_BUTTON_44, "Click here to abort SMBS (Stop Management by Slave)");
sc.SetCustomStudyControlBarButtonText(ACS_BUTTON_44, "Stop the Slave");
// wait for a button
if (sc.MenuEventID == ACS_BUTTON_44)
{
// reset button to off
sc.SetCustomStudyControlBarButtonEnable(sc.MenuEventID, 0);
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATED, 0);
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_JUNGFRAUENMODUS, 1);
eraseNoStopErrorMessage(sc);
return;
}
if (!(sc.GetBarHasClosedStatus(index) == BHCS_BAR_HAS_CLOSED))
{
return;
}
sc.SendOrdersToTradeService = !sc.GlobalTradeSimulationIsOn;
// check if we got activated by the deltazone wizard
// do nothing if not
if (!isActivated(sc)) {
return;
}
float zoneTop = sc.GetPersistentFloat(WORKERSLAVE_PERSISTENT_MONITORING_ZONE_TOP);
float zoneBottom = sc.GetPersistentFloat(WORKERSLAVE_PERSISTENT_MONITORING_ZONE_BOTTOM);
int tradingDirection = sc.GetPersistentInt(WORKERSLAVE_PERSISTENT_TRADING_DIRECTION);
float barClose = sc.BaseDataIn[SC_LAST][sc.Index];
float barLow = sc.BaseDataIn[SC_LOW][sc.Index];
float barHigh = sc.BaseDataIn[SC_HIGH][sc.Index];
// get current stop order (has to be attached!)
int currentStopOrderId = getCurrentStopOrderId(sc);
if (currentStopOrderId <= 0) {
sc.AddMessageToLog("Error: We are activated but no attached stop order was found. Exiting.", 1);
displayNoStopErrorMessage(sc);
return;
}
else {
eraseNoStopErrorMessage(sc);
}
// long case
if (tradingDirection == ORDER_TYPE_BUY) {
// 1: Wenn Low untertickt (aber nicht unterclosed), merken wir uns das und ziehen den Stop erst unter das low, und spaeter unter die Zone, sobald ein SK ueber der Zone gemacht wurde
// ABA NUR, WENN DER BISHERIGE STOP NICHT HÖHER IST
if (
sc.FormattedEvaluate(barLow, sc.BaseGraphValueFormat, LESS_OPERATOR, static_cast<float>(zoneBottom), sc.BaseGraphValueFormat) &&
!(sc.FormattedEvaluate(barClose, sc.BaseGraphValueFormat, LESS_OPERATOR, static_cast<float>(zoneBottom), sc.BaseGraphValueFormat))
) {
MessageText.Format("!! Price SPIKE below zone low. Adjusting stop to %.02f.", barLow - Input_AdjustOffset.GetInt() * sc.TickSize);
sc.AddMessageToLog(MessageText,0);
adjustStopPriceTo(sc, currentStopOrderId, barLow - Input_AdjustOffset.GetInt() * sc.TickSize, tradingDirection);
// activate post zone adjustment ... stop wieder unter die zone sobald oben raus
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATE_POST_ZONE_ADJUSTMENT, 1);
// fertig
return;
}
// 2: Wenn Low unterclosed, Stopp nachziehen unter das Low der Kerze, ABA NUR, WENN DER BISHERIGE STOP NICHT HÖHER IST
else if ( sc.FormattedEvaluate(barClose, sc.BaseGraphValueFormat, LESS_OPERATOR, static_cast<float>(zoneBottom), sc.BaseGraphValueFormat)) {
MessageText.Format("!! Price CLOSE below zone low. Adjusting stop to %.02f.", barLow - Input_AdjustOffset.GetInt() * sc.TickSize);
sc.AddMessageToLog(MessageText, 0);
adjustStopPriceTo(sc, currentStopOrderId, barLow - Input_AdjustOffset.GetInt() * sc.TickSize, tradingDirection);
}
// 3: wenn preis 10T ueber der Zone, den Sklaven wieder deaktivieren
else if (Input_AutoDeactivateStudyAfterLeavingZone.GetBoolean() && sc.FormattedEvaluate(barClose, sc.BaseGraphValueFormat, GREATER_OPERATOR, static_cast<float>(zoneTop + Input_StudyDeactivationOffset.GetInt() * sc.TickSize), sc.BaseGraphValueFormat)) {
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATED, 0);
if (sc.GetPersistentInt(WORKERSLAVE_PERSISTENT_JUNGFRAUENMODUS) == 1) {
// jungfraeulicher Stop, ziehen auf Zone -1
MessageText.Format("!! Auto-off after close above zone high. Adjusting stop to %.02f.", zoneBottom - 1 * sc.TickSize);
sc.AddMessageToLog(MessageText, 0);
adjustStopPriceTo(sc, currentStopOrderId, zoneBottom - 1 * sc.TickSize, tradingDirection);
}
}
// 4: es gab einen ausstopper und wir ziehen nach verlassen der zone den stop wieder unter die urspungszone
// else if (
// (sc.GetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATE_POST_ZONE_ADJUSTMENT) == 1) &&
// sc.FormattedEvaluate(barClose, sc.BaseGraphValueFormat, GREATER_OPERATOR, static_cast<float>(zoneTop), sc.BaseGraphValueFormat)
// ) {
// adjustStopPriceTo(sc, currentStopOrderId, zoneBottom - 1 * sc.TickSize);
// }
}
// short case
else if (tradingDirection == ORDER_TYPE_SELL) {
// 1: Wenn High uebertickt (aber nicht ueberclosed), merken wir uns das und ziehen den Stop erst unter das high, und spaeter ueber die Zone, sobald ein SK unter der Zone gemacht wurde
if (
sc.FormattedEvaluate(barHigh, sc.BaseGraphValueFormat, GREATER_OPERATOR, static_cast<float>(zoneTop), sc.BaseGraphValueFormat) &&
!(sc.FormattedEvaluate(barClose, sc.BaseGraphValueFormat, GREATER_OPERATOR, static_cast<float>(zoneTop), sc.BaseGraphValueFormat))
) {
MessageText.Format("!! Price SPIKE above zone high. Adjusting stop to %.02f.", barHigh + Input_AdjustOffset.GetInt() * sc.TickSize);
sc.AddMessageToLog(MessageText, 0);
adjustStopPriceTo(sc, currentStopOrderId, barHigh + Input_AdjustOffset.GetInt() * sc.TickSize, tradingDirection);
// activate post zone adjustment ... stop wieder ueber die zone sobald unten raus
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATE_POST_ZONE_ADJUSTMENT, 1);
// fertig
return;
}
// 2: Wenn High ueberclosed, Stopp nachziehen ueber das High der Kerze
else if (sc.FormattedEvaluate(barClose, sc.BaseGraphValueFormat, GREATER_OPERATOR, static_cast<float>(zoneTop), sc.BaseGraphValueFormat)) {
MessageText.Format("!! Price CLOSE above zone high. Adjusting stop to %.02f.", barHigh + Input_AdjustOffset.GetInt() * sc.TickSize);
sc.AddMessageToLog(MessageText, 0);
adjustStopPriceTo(sc, currentStopOrderId, barHigh + Input_AdjustOffset.GetInt() * sc.TickSize, tradingDirection);
}
// 3: wenn preis 10T unter der Zone, den Sklaven wieder deaktivieren
else if (Input_AutoDeactivateStudyAfterLeavingZone.GetBoolean() && sc.FormattedEvaluate(barClose, sc.BaseGraphValueFormat, LESS_OPERATOR, static_cast<float>(zoneBottom - Input_StudyDeactivationOffset.GetInt() * sc.TickSize), sc.BaseGraphValueFormat)) {
sc.SetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATED, 0);
if (sc.GetPersistentInt(WORKERSLAVE_PERSISTENT_JUNGFRAUENMODUS) == 1) {
MessageText.Format("!! Auto-off after close below zone low. Adjusting stop to %.02f.", zoneTop + 1 * sc.TickSize);
sc.AddMessageToLog(MessageText, 0);
// jungfraeulicher Stop, ziehen auf Zone -1
adjustStopPriceTo(sc, currentStopOrderId, zoneTop + 1 * sc.TickSize, tradingDirection);
}
}
// 4: es gab einen ausstopper und wir ziehen nach verlassen der zone den stop wieder ueber die urspungszone
// else if (
// (sc.GetPersistentInt(WORKERSLAVE_PERSISTENT_ACTIVATE_POST_ZONE_ADJUSTMENT) == 1) &&
// sc.FormattedEvaluate(barClose, sc.BaseGraphValueFormat, LESS_OPERATOR, static_cast<float>(zoneBottom), sc.BaseGraphValueFormat)
// ) {
// adjustStopPriceTo(sc, currentStopOrderId, zoneTop + 1 * sc.TickSize);
// }
}
}