Related
I'm sorting strings that are comprised of text and numbers.
I want the sort to sort the number parts as numbers, not alphanumeric.
For example I want: abc1def, ..., abc9def, abc10def
instead of: abc10def, abc1def, ..., abc9def
Does anyone know an algorithm for this (in particular in c++)
Thanks
I asked this exact question (although in Java) and got pointed to http://www.davekoelle.com/alphanum.html which has an algorithm and implementations of it in many languages.
Update 14 years later: Dave Koelle’s blog has gone off line and I can’t find his actual algorithm, but here’s an implementation.
https://github.com/cblanc/koelle-sort
Several natural sort implementations for C++ are available. A brief review:
natural_sort<> - based on Boost.Regex.
In my tests, it's roughly 20 times slower than other options.
Dirk Jagdmann's alnum.hpp, based on Dave Koelle's alphanum algorithm
Potential integer overlow issues for values over MAXINT
Martin Pool's natsort - written in C, but trivially usable from C++.
The only C/C++ implementation I've seen to offer a case insensitive version, which would seem to be a high priority for a "natural" sort.
Like the other implementations, it doesn't actually parse decimal points, but it does special case leading zeroes (anything with a leading 0 is assumed to be a fraction), which is a little weird but potentially useful.
PHP uses this algorithm.
This is known as natural sorting. There's an algorithm here that looks promising.
Be careful of problems with non-ASCII characters (see Jeff's blog entry on the subject).
Partially reposting my another answer:
bool compareNat(const std::string& a, const std::string& b){
if (a.empty())
return true;
if (b.empty())
return false;
if (std::isdigit(a[0]) && !std::isdigit(b[0]))
return true;
if (!std::isdigit(a[0]) && std::isdigit(b[0]))
return false;
if (!std::isdigit(a[0]) && !std::isdigit(b[0]))
{
if (a[0] == b[0])
return compareNat(a.substr(1), b.substr(1));
return (toUpper(a) < toUpper(b));
//toUpper() is a function to convert a std::string to uppercase.
}
// Both strings begin with digit --> parse both numbers
std::istringstream issa(a);
std::istringstream issb(b);
int ia, ib;
issa >> ia;
issb >> ib;
if (ia != ib)
return ia < ib;
// Numbers are the same --> remove numbers and recurse
std::string anew, bnew;
std::getline(issa, anew);
std::getline(issb, bnew);
return (compareNat(anew, bnew));
}
toUpper() function:
std::string toUpper(std::string s){
for(int i=0;i<(int)s.length();i++){s[i]=toupper(s[i]);}
return s;
}
Usage:
std::vector<std::string> str;
str.push_back("abc1def");
str.push_back("abc10def");
...
std::sort(str.begin(), str.end(), compareNat);
To solve what is essentially a parsing problem a state machine (aka finite state automaton) is the way to go. Dissatisfied with the above solutions i wrote a simple one-pass early bail-out algorithm that beats C/C++ variants suggested above in terms of performance, does not suffer from numerical datatype overflow errors, and is easy to modify to add case insensitivity if required.
sources can be found here
For those that arrive here and are already using Qt in their project, you can use the QCollator class. See this question for details.
Avalanchesort is a recursive variation of naturall sort, whiche merge runs, while exploring the stack of sorting-datas. The algorithim will sort stable, even if you add datas to your sorting-heap, while the algorithm is running/sorting.
The search-principle is simple. Only merge runs with the same rank.
After finding the first two naturell runs (rank 0), avalanchesort merge them to a run with rank 1. Then it call avalanchesort, to generate a second run with rank 1 and merge the two runs to a run with rank 2. Then it call the avalancheSort to generate a run with rank 2 on the unsorted datas....
My Implementation porthd/avalanchesort divide the sorting from the handling of the data using interface injection. You can use the algorithmn for datastructures like array, associative arrays or lists.
/**
* #param DataListAvalancheSortInterface $dataList
* #param DataRangeInterface $beginRange
* #param int $avalancheIndex
* #return bool
*/
public function startAvalancheSort(DataListAvalancheSortInterface $dataList)
{
$avalancheIndex = 0;
$rangeResult = $this->avalancheSort($dataList, $dataList->getFirstIdent(), $avalancheIndex);
if (!$dataList->isLastIdent($rangeResult->getStop())) {
do {
$avalancheIndex++;
$lastIdent = $rangeResult->getStop();
if ($dataList->isLastIdent($lastIdent)) {
$rangeResult = new $this->rangeClass();
$rangeResult->setStart($dataList->getFirstIdent());
$rangeResult->setStop($dataList->getLastIdent());
break;
}
$nextIdent = $dataList->getNextIdent($lastIdent);
$rangeFollow = $this->avalancheSort($dataList, $nextIdent, $avalancheIndex);
$rangeResult = $this->mergeAvalanche($dataList, $rangeResult, $rangeFollow);
} while (true);
}
return $rangeResult;
}
/**
* #param DataListAvalancheSortInterface $dataList
* #param DataRangeInterface $range
* #return DataRangeInterface
*/
protected function findRun(DataListAvalancheSortInterface $dataList,
$startIdent)
{
$result = new $this->rangeClass();
$result->setStart($startIdent);
$result->setStop($startIdent);
do {
if ($dataList->isLastIdent($result->getStop())) {
break;
}
$nextIdent = $dataList->getNextIdent($result->getStop());
if ($dataList->oddLowerEqualThanEven(
$dataList->getDataItem($result->getStop()),
$dataList->getDataItem($nextIdent)
)) {
$result->setStop($nextIdent);
} else {
break;
}
} while (true);
return $result;
}
/**
* #param DataListAvalancheSortInterface $dataList
* #param $beginIdent
* #param int $avalancheIndex
* #return DataRangeInterface|mixed
*/
protected function avalancheSort(DataListAvalancheSortInterface $dataList,
$beginIdent,
int $avalancheIndex = 0)
{
if ($avalancheIndex === 0) {
$rangeFirst = $this->findRun($dataList, $beginIdent);
if ($dataList->isLastIdent($rangeFirst->getStop())) {
// it is the last run
$rangeResult = $rangeFirst;
} else {
$nextIdent = $dataList->getNextIdent($rangeFirst->getStop());
$rangeSecond = $this->findRun($dataList, $nextIdent);
$rangeResult = $this->mergeAvalanche($dataList, $rangeFirst, $rangeSecond);
}
} else {
$rangeFirst = $this->avalancheSort($dataList,
$beginIdent,
($avalancheIndex - 1)
);
if ($dataList->isLastIdent($rangeFirst->getStop())) {
$rangeResult = $rangeFirst;
} else {
$nextIdent = $dataList->getNextIdent($rangeFirst->getStop());
$rangeSecond = $this->avalancheSort($dataList,
$nextIdent,
($avalancheIndex - 1)
);
$rangeResult = $this->mergeAvalanche($dataList, $rangeFirst, $rangeSecond);
}
}
return $rangeResult;
}
protected function mergeAvalanche(DataListAvalancheSortInterface $dataList, $oddListRange, $evenListRange)
{
$resultRange = new $this->rangeClass();
$oddNextIdent = $oddListRange->getStart();
$oddStopIdent = $oddListRange->getStop();
$evenNextIdent = $evenListRange->getStart();
$evenStopIdent = $evenListRange->getStop();
$dataList->initNewListPart($oddListRange, $evenListRange);
do {
if ($dataList->oddLowerEqualThanEven(
$dataList->getDataItem($oddNextIdent),
$dataList->getDataItem($evenNextIdent)
)) {
$dataList->addListPart($oddNextIdent);
if ($oddNextIdent === $oddStopIdent) {
$restTail = $evenNextIdent;
$stopTail = $evenStopIdent;
break;
}
$oddNextIdent = $dataList->getNextIdent($oddNextIdent);
} else {
$dataList->addListPart($evenNextIdent);
if ($evenNextIdent === $evenStopIdent) {
$restTail = $oddNextIdent;
$stopTail = $oddStopIdent;
break;
}
$evenNextIdent = $dataList->getNextIdent($evenNextIdent);
}
} while (true);
while ($stopTail !== $restTail) {
$dataList->addListPart($restTail);
$restTail = $dataList->getNextIdent($restTail);
}
$dataList->addListPart($restTail);
$dataList->cascadeDataListChange($resultRange);
return $resultRange;
}
}
My algorithm with test code of java version. If you want to use it in your project you can define a comparator yourself.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
public class FileNameSortTest {
private static List<String> names = Arrays.asList(
"A__01__02",
"A__2__02",
"A__1__23",
"A__11__23",
"A__3++++",
"B__1__02",
"B__22_13",
"1_22_2222",
"12_222_222",
"2222222222",
"1.sadasdsadsa",
"11.asdasdasdasdasd",
"2.sadsadasdsad",
"22.sadasdasdsadsa",
"3.asdasdsadsadsa",
"adsadsadsasd1",
"adsadsadsasd10",
"adsadsadsasd3",
"adsadsadsasd02"
);
public static void main(String...args) {
List<File> files = new ArrayList<>();
names.forEach(s -> {
File f = new File(s);
try {
if (!f.exists()) {
f.createNewFile();
}
files.add(f);
} catch (IOException e) {
e.printStackTrace();
}
});
files.sort(Comparator.comparing(File::getName));
files.forEach(f -> System.out.print(f.getName() + " "));
System.out.println();
files.sort(new Comparator<File>() {
boolean caseSensitive = false;
int SPAN_OF_CASES = 'a' - 'A';
#Override
public int compare(File left, File right) {
char[] csLeft = left.getName().toCharArray(), csRight = right.getName().toCharArray();
boolean isNumberRegion = false;
int diff=0, i=0, j=0, lenLeft=csLeft.length, lenRight=csRight.length;
char cLeft = 0, cRight = 0;
for (; i<lenLeft && j<lenRight; i++, j++) {
cLeft = getCharByCaseSensitive(csLeft[i]);
cRight = getCharByCaseSensitive(csRight[j]);
boolean isNumericLeft = isNumeric(cLeft), isNumericRight = isNumeric(cRight);
if (isNumericLeft && isNumericRight) {
// Number start!
if (!isNumberRegion) {
isNumberRegion = true;
// Remove prefix '0'
while (i < lenLeft && cLeft == '0') i++;
while (j < lenRight && cRight == '0') j++;
if (i == lenLeft || j == lenRight) break;
}
// Diff start: calculate the diff value.
if (cLeft != cRight && diff == 0)
diff = cLeft - cRight;
} else {
if (isNumericLeft != isNumericRight) {
// One numeric and one char.
if (isNumberRegion)
return isNumericLeft ? 1 : -1;
return cLeft - cRight;
} else {
// Two chars: if (number) diff don't equal 0 return it.
if (diff != 0)
return diff;
// Calculate chars diff.
diff = cLeft - cRight;
if (diff != 0)
return diff;
// Reset!
isNumberRegion = false;
diff = 0;
}
}
}
// The longer one will be put backwards.
return (i == lenLeft && j == lenRight) ? cLeft - cRight : (i == lenLeft ? -1 : 1) ;
}
private boolean isNumeric(char c) {
return c >= '0' && c <= '9';
}
private char getCharByCaseSensitive(char c) {
return caseSensitive ? c : (c >= 'A' && c <= 'Z' ? (char) (c + SPAN_OF_CASES) : c);
}
});
files.forEach(f -> System.out.print(f.getName() + " "));
}
}
The output is,
1.sadasdsadsa 11.asdasdasdasdasd 12_222_222 1_22_2222 2.sadsadasdsad 22.sadasdasdsadsa 2222222222 3.asdasdsadsadsa A__01__02 A__11__23 A__1__23 A__2__02 A__3++++ B__1__02 B__22_13 adsadsadsasd02 adsadsadsasd1 adsadsadsasd10 adsadsadsasd3
1.sadasdsadsa 1_22_2222 2.sadsadasdsad 3.asdasdsadsadsa 11.asdasdasdasdasd 12_222_222 22.sadasdasdsadsa 2222222222 A__01__02 A__1__23 A__2__02 A__3++++ A__11__23 adsadsadsasd02 adsadsadsasd1 adsadsadsasd3 adsadsadsasd10 B__1__02 B__22_13
Process finished with exit code 0
// -1: s0 < s1; 0: s0 == s1; 1: s0 > s1
static int numericCompare(const string &s0, const string &s1) {
size_t i = 0, j = 0;
for (; i < s0.size() && j < s1.size();) {
string t0(1, s0[i++]);
while (i < s0.size() && !(isdigit(t0[0]) ^ isdigit(s0[i]))) {
t0.push_back(s0[i++]);
}
string t1(1, s1[j++]);
while (j < s1.size() && !(isdigit(t1[0]) ^ isdigit(s1[j]))) {
t1.push_back(s1[j++]);
}
if (isdigit(t0[0]) && isdigit(t1[0])) {
size_t p0 = t0.find_first_not_of('0');
size_t p1 = t1.find_first_not_of('0');
t0 = p0 == string::npos ? "" : t0.substr(p0);
t1 = p1 == string::npos ? "" : t1.substr(p1);
if (t0.size() != t1.size()) {
return t0.size() < t1.size() ? -1 : 1;
}
}
if (t0 != t1) {
return t0 < t1 ? -1 : 1;
}
}
return i == s0.size() && j == s1.size() ? 0 : i != s0.size() ? 1 : -1;
}
I am not very sure if it is you want, anyway, you can have a try:-)
I wrote the following code to look through the last 100 candlesticks and draw a rectangle around a bullish engulfing candlestick patterns. I hope extend it for bearish engulfing pattern too. I don't know why, but the rectangles don't draw. Please take a look at the code below
bool isBullishEngulfing(int current) {
if((iClose(_Symbol,0,current) > iOpen(_Symbol,0,current)) && (iClose(_Symbol,0,current + 1) < iOpen(_Symbol,0,current + 1)) &&
(iOpen(_Symbol,0,current) < iClose(_Symbol,0,current + 1)) && (iClose(_Symbol,0,current) > iOpen(_Symbol,0,current + 1)))
return true;
return false;
}
void showRectangles() {
for (int i=100;i<=1;i--) {
if(isBullishEngulfing(i)) {
drawBullRectangle(i,iHigh(_Symbol,0,i),iLow(_Symbol,0,i));
}
}
}
bool drawBullRectangle(int candleInt,const double top,const double bottom)
{
const datetime starts=iTime(_Symbol,0,candleInt);
const datetime ends=starts+PeriodSeconds()*Numbars; //Numbars shows how long the rectangle should draw
const string name=prefix+"_"+(candleInt>0?"DEMAND":"SUPPLY")+"_"+TimeToString(starts);
if(!ObjectCreate(0,name,OBJ_RECTANGLE,0,0,0,0,0))
{
printf("%i %s: failed to create %s. error=%d",__LINE__,__FILE__,name,_LastError);
return false;
}
ObjectSetInteger(0,name,OBJPROP_TIME1,starts);
ObjectSetInteger(0,name,OBJPROP_TIME2,ends);
ObjectSetDouble(0,name,OBJPROP_PRICE1,top);
ObjectSetDouble(0,name,OBJPROP_PRICE2,bottom);
ObjectSetInteger(0,name,OBJPROP_COLOR, clrAqua);
ObjectSetInteger(0,name,OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
ObjectSetInteger(0,name,OBJPROP_FILL, true);
return true;
}
void OnDeinit(const int reason){ObjectsDeleteAll(0,prefix);}
void OnTick()
{
if(!isNewBar())
return; //not necessary but waste of time to check every second
showRectangles();
}
bool isNewBar()
{
static datetime lastbar;
datetime curbar = (datetime)SeriesInfoInteger(_Symbol,_Period,SERIES_LASTBAR_DATE);
if(lastbar != curbar)
{
lastbar = curbar;
return true;
}
return false;
}
I would appreciate help to resolve this.
The error is mainly in the loop, it should be for (int i=100;i>=1;i--)
The other "possible" error is in the logic of theisBullishEngulfing() function.
Usually, the Close of the previous bar is equal to the Open of the current bar, so the following condition doesn't get fulfilled(most of the time)
iOpen(_Symbol,0,current) < iClose(_Symbol,0,current + 1)
(So, I suggest to remove this line, but this is just a suggestion, note there are occasions that your condition get fulfilled as well)
I am really new to MQL4, and still trying to grasp the concept. I would want to have an event handler to detect every candle bar opening (or every previous candle bar closing). Trying to wrap that around my head but it is not working:
So I have a function to check for the tick:
bool checkingFirstTick(){
datetime currentTime = iTime(Symbol(), Period(), 0);
if(currentTime - lastCandle > 0){
lastCandle = currentTime;
return true;
}
return false;
}
where lastCandle is a global variable.
Now when I put it into the OnTick() event:
void OnTick(){
Print("Ticking");
if(checkingFirstTick()){
Print("It's an opening!");
}
}
The It's an opening! statement never get printed.
Am I doing something fundamentally wrong? Or is there any more efficient way to listen to an opening of the candle bar, no matter what is the period I set?
Try this:
// --- Global Variable ----
datetime ArrayTime[], LastTime;
void OnTick() {
if(NewBar(PERIOD_H1)) {
// insert your program here
}
}
bool NewBar(int period) {
bool firstRun = false, newBar = false;
ArraySetAsSeries(ArrayTime,true);
CopyTime(Symbol(),period,0,2,ArrayTime);
if(LastTime == 0) firstRun = true;
if(ArrayTime[0] > LastTime) {
if(firstRun == false) newBar = true;
LastTime = ArrayTime[0];
}
return newBar;
}
I am trying to code my EA where if my close conditions are met, I want my EA to close all the open trades ( there are potentially more than 1 open trades ).
Here is my code for the closing trade section and when I run it through the Strategy Tester, I noticed it doesn't close my trades.
Total=0; // Amount of orders
for(int i=1; i<=OrdersTotal(); i++) // Loop through orders
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // If there is the next one
{ // Analyzing orders:
if (OrderSymbol()!=Symb)continue; // Another security
Total++; // Counter of market orders
}
}
while(true) // Loop of closing orders
{
if (OrderType()==0 && Close_Buy_Condition==true) // Order Buy is opened & Close Buy Condition is true
{
for (c=Total-1; c>=0; c--)
{
RefreshRates(); // Refresh rates
Ans=OrderClose(OrderTicket(),Lot,Bid,Slippage); // Closing Buy
}
}
if (OrderType()==1 && Close_Sell_Condition==true) // Order Sell is opened & Close Sell Condition is true
{
for (d=Total-1; d>=0; d--)
{
RefreshRates(); // Refresh rates
Ans=OrderClose(OrderTicket(),Lot,Ask,Slippage); // Closing Sell
}
}
break; // Exit while
}
I don't know where do you set value for Ask, Bid and Lot variables. But they've to change when you loop through your open positions.
You can try this function to close all positions:
bool CloseAllPositions()
{
double total;
int cnt;
while(OrdersTotal()>0)
{
// Close pending orders first, you can remove this section if you don't want pending orders to be deleted
total=OrdersTotal();
for(cnt=total-1; cnt>=0; cnt--)
{
if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES))
{
switch(OrderType())
{
case OP_BUYLIMIT :OrderDelete(OrderTicket()); break;
case OP_SELLLIMIT :OrderDelete(OrderTicket()); break;
case OP_BUYSTOP :OrderDelete(OrderTicket()); break;
case OP_SELLSTOP :OrderDelete(OrderTicket()); break;
}
}
}
// then close opened orders
total=OrdersTotal();
for(cnt=total-1; cnt>=0; cnt--)
{
if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES))
{
switch(OrderType())
{
case OP_BUY:
if (Close_Buy_Condition==true) {
OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_BID),3,Violet);
}
break;
case OP_SELL:
if (Close_Sell_Condition==true) {
OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_ASK),3,Violet);
}
break;
}
}
}
}
return true;
}
Edit:
if you don't want to deal with pending orders at all, use this code instead of OrdersTotal():
int GetNumOpenPositions() {
int total = OrdersTotal();
double OpenBuyOrders = 0, OpenSellOrders = 0, PendBuys =0, PendSells =0;
for( i=0;i<total;i++)
{
OrderSelect(i, SELECT_BY_POS );
if ( OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
int type = OrderType();
if (type == OP_BUY ) {OpenBuyOrders=OpenBuyOrders+1;}
if (type == OP_SELL ) {OpenSellOrders=OpenSellOrders+1;}
if (type == OP_BUYSTOP ) {PendBuys=PendBuys+1;}
if (type == OP_SELLSTOP ) {PendSells=PendSells+1;}
}
}
return (OpenBuyOrders + OpenSellOrders);
}
Then total orders would be
I have a java app that runs an infinite while loop. When I click run on eclipse it seems to be reverting to old code that I have changed. The thing is, when I build it updates at random times. The latest time I added System.exit(). I changed the code and it still exits. I have also tried this program in C#. I feel that I am somehow confusing the language runtime with the infinite while loop. The program works on a series of changing boolean values. The main action I am looking at the erratic behavior (this was what was happening before I added System.exit()) is in a method that iterates pixels in a BufferedImage. I am running Ubuntu 14.10. I have tried making a new project and pasting the same code (could it be invisible chars somehow?) I am very confused and would be happy if someone could help.
while(true){
if (bool1 && !exe.isSeparate(image))
{
// change boolean values
// did run System.exit(0)
}
if (bool2 && !exe.isSeparate(image))
{
// change boolean values
// did run System.exit(0)
}
}
boolean isSeparate(BufferedImage image)
{
int x = touchingX;
boolean first = false, second = false, third = false;
int startAt = this.getYStart(image);
for (int y = startAt; y < startAt + 150; y++)
{
Color pixel = new Color(image.getRGB(x, y));
if (!(pixel.getRed() == 255 && pixel.getGreen() == 255 && pixel.getBlue() == 255)
&& !(pixel.getRed() == 0 && pixel.getGreen() == 68 && pixel.getBlue() == 125))
{
if (!first)
{
first = true;
}
if (first && second && !third)
{
third = true;
}
}
else
{
if (first && !second)
{
second = true;
}
}
}
if (first && second && third)
{
return true;
}
return false;
}
I have answered my question. Ironically, it was a logic error.