MQL4 How can I return the current profit on an open order based on the order comment - mql4

I'm trying to return the current profit on an open order based on the order comment.
Right now, my code below but is getting the profit of all open orders as opposed to just the order with a specific comment.
So, what I want to return is the profit for the order that the order comment is "Testing".
double Profit=0;
for(int i=0; i<OrdersTotal(); i++ )
{
if(OrderSelect(i, SELECT_BY_POS)==true)
{
if (OrderComment()=="Testing")
Profit+= (OrderProfit()+OrderSwap()+OrderCommission());
}

You should not use OrderComment() for isolating/identifying trades, the broker can overwrite/alter/delete the comments at any time for any reason.
You should also count orders down, not up. If an order is deleted or created mid check, your function will exit with an error or produce unexpected results.
All the above given, the following works when I've tested it.
double Profit=0;
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS))
{
if(OrderComment()=="Testing") Profit+= (OrderProfit()-OrderSwap()-OrderCommission());
}
}
Comment(Profit);

Related

Highlight near duplicate in conditional formating to highlight values with one character difference

I'm currently using this formula to highlight duplicates in my spreadsheet.
=ARRAYFORMULA(COUNTIF(A$2:$A2,$A2)>1)
Quite simple, it allows me to skip the first occurrence and only highlight 2nd, 3rd, ... occurrences.
I would like the formula to go a bit further and highlight near duplicates as well.
Meaning if there is only one character difference between 2 cells, then it should be considered as a duplicate.
For instance: "Marketing", "Marketng", "Marketingg" and "Market ing" would all be considered the same.
I've made a sample sheet in case my requirement is not straightforward to understand.
Thanks in advance.
Answer
Unfortunately, it is not possible to do this only through Formulas. Apps Scripts are need as well. The process for achieving your desired results is described below.
In Google Sheets, go to Extensions > Apps Script, paste the following code1 and save.
function TypoFinder(range, word) { // created by https://stackoverflow.com/users/19361936
if (!Array.isArray(range) || word == "") {
return false;
}
distances = range.map(row => row.map(cell => Levenshtein(cell, word))) // Iterate over range and check Levenshtein distance.
var accumulator = 0;
for (var i = 0; i < distances.length; i++) {
if (distances[i] < 2) {
accumulator++
} // Keep track of how many times there's a Levenshtein distance of 0 or 1.
}
return accumulator > 1;
}
function Levenshtein(a, b) { // created by https://stackoverflow.com/users/4269081
if (a.length == 0) return b.length;
if (b.length == 0) return a.length;
// swap to save some memory O(min(a,b)) instead of O(a)
if (a.length > b.length) {
var tmp = a;
a = b;
b = tmp;
}
var row = [];
// init the row
for (var i = 0; i <= a.length; i++) {
row[i] = i;
}
// fill in the rest
for (var i = 0; i < b.length; i++) {
var prev = i;
for (var j = 0; j < a.length; j++) {
var val;
if (b.charAt(i) == a.charAt(j)) {
val = row[j]; // match
} else {
val = Math.min(row[j] + 1, // substitution
prev + 1, // insertion
row[j + 1] + 1); // deletion
}
row[j] = prev;
prev = val;
}
row[a.length] = prev;
}
return row[a.length];
}
In cell B1, enter =TypoFinder($A$2:$A2,$A2). Autofill that formula down the column by draggin.
Create a conditional formatting rule for column A. Using Format Rules > Custom Formula, enter =B2:B.
At this point, you might wish to hide column B. To do so, right click on the column and press Hide Column.
The above explanation assumes the column you wish to highlight is Column A and the helper column is column B. Adjust appropriately.
Note that I have assumed you do not wish to highlight repeated blank columns as duplicate. If I am incorrect, remove || word == "" from line 2 of the provided snippet.
Explanation
The concept you have described is called Levenshtein Distance, which is a measure of how close together two strings are. There is no built-in way for Google Sheets to process this, so the Levenshtein() portion of the snippet above implements a custom function to do so instead. Then the TypoFinder() function is built on top of it, providing a method for evaluating a range of data against a specified "correct" word (looking for typos anywhere in the range).
Next, a helper column is used because Sheets has difficulties parsing custom formulas as part of a conditional formatting rule. Finally, the rule itself is implemented to check the helper column's determination of whether the row should be highlighted or not. Altogether, this highlights near-duplicate results in a specified column.
1 Adapted from duality's answer to a related question.

How to close a trade for sure in MQL4/MT4?

I have an EA with closes a trade on button click
//void CloseCurrentTrade(). It's called after successfull OrderSelect
int orderType = OrderType();
double price;
if (orderType == OP_BUY)
price = return MarketInfo(OrderSymbol(), MODE_BID);
else if (orderType == OP_SELL)
price = return MarketInfo(OrderSymbol(), MODE_ASK);
else
return;
int slippage = 20;
bool closed = OrderClose(OrderTicket(), OrderLots(), price, slippage);
if (closed)
return;
int lastError = GetLastError();
Sometimes it closes the trade and sometimes it returns error #129 (Invalid price). I can't figure out why. Most of the cases people just misuse bid/ask or don't have enouth slippage. I've try to use slippage up to 200, still the same error. Some EA's just try to close it several times (and it looks like a hack for me), but it does not help as well. There are some mentions that you need to call RefreshRates() before bid/ask, but documentaion says that you don't need to do that for MarketInfo.
I've run out of ideas what it could be. Why it can happen and how to avoid that? I'm testing it on FXCM Demo (if it is the case).
First make sure that you've selected the order properly, and try to use OrderClosePrice where possible(this will eliminate the need for checking the OP_SELL/OP_BUY)
//+------------------------------------------------------------------+
//| Close the latest order for this current symbol |
//+------------------------------------------------------------------+
void CloseCurrentTrade()
{
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderSymbol()!=Symbol()) continue;
if(OrderMagicNumber()!=MagicNum) continue; // if there is no magic number set, then no need for this(manual orders)
if(OrderType()>OP_SELL) continue;
if(!OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slippage))
Print("Error in Closing the Order, Error : ",ErrorDescription(GetLastError()));
break; // assuming you want to close the latest trade only, exit the order closing loop
}
}
Also note that your broker might have restrictions on how far the closing price must be from the Order Opened price and other levels(sl/tp), in order to close an order. Refer here
Print and compare Ask/Bid && price when closed!=true. Beware that MarketInfo mode data is stored at Ask/Bid predefined variables already, so you can eliminate that if you OrderSelect in current symbol.

GKTurnBasedMatch doesn't consistently advance to the next player (Xamarin, Apple GameKit)

I'm using a turn-based match for a board game, and when a turn is complete I call GKTurnBasedMatch.EndTurn and pass the match participants and the new match data as the arguments. I need the game to advance to the unmatched players, but it only does so after some indeterminate time related to the timeout value. Setting the timeout value 0 only prevents the game from ever progressing past player 1. The match data is being updated, so the app is definitely communicating with Game Center servers. What am I missing here?
private void endTurn(double timeout)
{
// Copies list of participants to a mutable array
GKTurnBasedParticipant[] Participants = new GKTurnBasedParticipant[match.Participants.Length];
match.Participants.CopyTo(Participants, 0);
// Advances to the next player
match.EndTurn(Participants, timeout, matchData, (e) =>
{
// If there is an error message, print it to the console
if (e != null)
{
Console.WriteLine(e.LocalizedDescription);
Console.WriteLine(e.LocalizedFailureReason);
}
// Otherwise proceed normally
else
turnOverUpdate();
});
}
Apple's documentation is quite poor for the EndTurn method, but I figured it out. The NextParticipants field should be treated like EndTurnWithNextParticipant, so you have to copy GKTurnBasedMatch.Participants and reorder it so the next player is first and so fourth. The match only gives you the participants in order of joining, not relative to the local player, so you have to sort it. Below is the code I used to accomplish this.
List<GKTurnBasedParticipant> participants = new List<GKTurnBasedParticipant>();
// Gets the index of the local player
int index = 0;
for (int i = 0; i < match.Participants.Length; i++)
{
if (match.Participants[i].Player != null)
{
if (match.Participants[i].Player.PlayerID == GKLocalPlayer.LocalPlayer.PlayerID)
{
index = i;
break;
}
}
}
int offset = match.Participants.Length - index;
for (int i = 1; i < offset; i++)
participants.Add(match.Participants[i + index]);
for (int i = 0; i <= index; i++)
participants.Add(match.Participants[i]);
GKTurnBasedParticipant[] nextParticipants = participants.ToArray();

how to disable multi-column sort in ui-grid

I have a client who specifically does not like the numbers next in the headers of the columns when doing a sort. This is rooted in UI-Grid's multi-sort, which gives each column a numbered priority. Is there a way to disable the multi-sort in order to remove those numbers? I still want to keep sorting activated, but only on one column at a time.
Thanks.
I've had this problem myself. If you look carefully in the ui0grid.js code you'll see that there is (at this time) no option to diable it. The writers of ui-grid state that they would welcome a request for such a function in this thread
However, you want a fix, not a promise ;-)
You can spot how many sortColumns have been chosen in the sortChanged method.
Try something like this:
$scope.gridOptions.onRegisterApi = function(gridApi) {
$scope.gridApi = gridApi;
// Register a handler that is fired everytime someone changd the sort params.
$scope.gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
if (sortColumns.length > 1) {
// We have more than one sort. Kill the first one.
// If this works we'll only ever have 0, 1 or 2 sortColumns,
// and only ever 2 for the lifetime of this method.
var column = null;
for (var j = 0; j < grid.columns.length; j++) {
if (grid.columns[j].name === sortColumns[0].field) {
column = grid.columns[j];
break;
}
}
if (column) {
sortColumns[1].sort.priority = 1; // have to do this otherwise the priority keeps going up.
column.unsort();
}
}
});
};
This is against the 3.0.0 release of ui-grid.
HTH
To prevent sorting on multiple columns, I added these two lines in the Grid.prototype.sortColumn function, ui-grid.js file.
self.resetColumnSorting(column);
column.sort.priority = undefined;
works for me..
I wanted to limit multiple sort columns to a maximum of 2. This is how I did it.
$scope.gridOptions.onRegisterApi = function(gridApi) {
$scope.gridApi = gridApi;
$scope.gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
if (sortColumns.length == 3) {
//limit multi column sort to max 2 columns
for (var j = 0; j < grid.columns.length; j++) {
if (grid.columns[j].name === sortColumns[2].name) {
grid.columns[j].sort = {};
break;
}
}
return;
});
};
Looks like this is supported now in the HTML element:
[suppressMultiSort]="true"
This in the latest version. No need for tough scripts.

Parsing with Awesomium

the awesomium answering forums seem pretty much dead, so I'm reposting this here
First of all, before starting to learn Awesomium I used the HtmlAgilityPack library for all my parsing needs, but the library is not being updated anymore and I decided to move to Awesomium. (so my approach is based on my experience with HAP)
I figured out how to parse lists of objects with Awesomium, but I can't figure out how to work with them. For example:
public dynamic FindNodes(string xpath, dynamic node = null, WebView wv = null)
{
if (wv == null) wv = mainView;
dynamic nodes = (JSObject)wv.ExecuteJavascriptWithResult(String.Format("document.evaluate(\"{0}\", {1}, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)", xpath, "document")));
int length = nodes.snapshotLength;
for (int i = 0; i < length; i++)
{
Console.WriteLine(nodes.snapshotItem(i).innerText);
}
return nodes;
}
The problems start after I return the nodes. I want to perform a series of searches for each node, so after returning them I decided that the following should work:
dynamic weakCounters = ap.FindNodes("//div[#id='weaklist']/ul/li");
for (int i = 0; i < weakCounters.snapshotLength; i++)
{
ap.FindNodes("//h3[#class='black']", weakCounters.snapshotItem(i));
}
But it did not. The part where I'm trying to get the length of the list and of course, if I try to get a snapshot of the item directly I get an error.
I understand, that I'm making a HUGE mistake somewhere. I just can't understand where.
Edit: Surprisingly if I do the following, everything seems fine, but it just doesn't look right to create a new variable everytime I need to access it (that's just bananas)
dynamic weakCounters = ap.FindNodes("//div[#id='weaklist']/ul/li");
dynamic nodes = weakCounters;
for (int i = 0; i < nodes.snapshotLength; i++)
{
Also, how can I pass the result (element) that I have extracted back to awesomium so that I could do a "subsearch" ?
cross-posted answer from http://answers.awesomium.com/questions/4276/parsing-with-awesomium.html
Why do you need Awesomium for HTML parsing? What's wrong with
HtmlAgilityPack?
Download page with Awesomium (if that is why you need it), get HTML,
parse it with HtmlAgilityPack.
Parsing like this should be very slow (if it return many elements).

Resources