MT4 export script - export

The following MQL4 script exports data from MetaTrader to a csv file. Unfortunately ( for me at least ), the order of the data in the generated csv file from 0 to 1000, 0 being the most recent ( present to past ). I want the file to be sorted from 1000 to 0 ( past to present ).
I altered the write data loop below to: for (int bar=Export_Bars; bar==0 bar--) but this simply generated an empty csv file.
#property script_show_inputs
input string Export_FileName = "data\\data.csv";
input int Export_Bars = 20000;
input int StartHour = 10;
input int EndHour = 19;
void OnStart()
{
int file = FileOpen(Export_FileName, FILE_WRITE|FILE_CSV|FILE_ANSI, ',');
if (file != INVALID_HANDLE && (Hour() >= StartHour) && Hour() < EndHour)
{
// Write the header of data
string row="";
for (int i=0; i<=5; i++)
{
if (StringLen(row))
row += ",";
row += "Open"+i+",High"+i+",Low"+i+",Close"+i;
}
FileWrite(file, row);
// Copy all required information from the history
MqlRates rates[], rate;
int count = Export_Bars + 5;
if (CopyRates(Symbol(), Period(), 1, count, rates) < count)
{
Print("Error! Not enough history size for exporting required information.");
return;
}
ArraySetAsSeries(rates, true);
// Write data
for (int bar=0; bar<Export_Bars; bar++)
{
row="";
double zlevel=0;
for (int y=0; y<=5; y++)
{
if (StringLen(row))
row += ",";
rate = rates[bar+y];
if (y==0)
zlevel = rate.open; // level of price calculation
row += NormalizeDouble(rate.open -zlevel, Digits()) + ","
+ NormalizeDouble(rate.high -zlevel, Digits()) + ","
+ NormalizeDouble(rate.low -zlevel, Digits()) + ","
+ NormalizeDouble(rate.close-zlevel, Digits());
}
FileWrite(file, row);
}
FileClose(file);
Print("Export of data is finished successfully.");
} else Print("Error! Failed to create the file for data export. ", GetLastError());
}
So my question what changes need to be made to the script in order to export data in the past to present order?

Change the Loop Constructor for a Time-Reverse-Iterator stepping:
for ( int bar = Export_Bars - 1; // .LOOP-INIT(s)
bar >= 0; // .LOOP-RUN-PRE-CONDITION
bar-- // .LOOP-RUN-POST-UPDATE(s)
) {...} // .LOOP-RUN-BODY

Related

why is this else block executed twice?

I have the following code which correctly calculates the jaccard similarity between an input char array and an existing array of char arrays. jacc_sim_rec[] is used to record the similarities which satisfy a minimum threshold value. The for loop is used to iterate through the multidimensional array and the loop is supposed to continue checking similarity if minimum threshold is not satisfied at if (jacc_sim < SIM_THRESHOLD); else record the result at
else
{
jacc_sim_rec[j] = jacc_sim;//keep record of similarity
++j;//record number of highly similar elements
}
my problem is, the whole statements in the else block is executed twice every time the threshold value is satisfied.
int j=0;
void calc_jac_sim( char*INCOMING, int grp)
{
unsigned long i, j11 = 0, j01 = 0, j10 = 0,m=0;
char *m11, *m01, *m10;
float jacc_sim = 0.0;
char r1[SBF_LEN] = { NULL };
char r2[SBF_LEN] = { NULL };
char r3[SBF_LEN] = { NULL };
int cnt = SBF_LEN - 1;
clear_jacc_sim_info();
for (int i = 0; i <= SBF_REC[grp]; ++i)
{
while (cnt >= 0)
{
r1[cnt] = SBF[grp][i][cnt] & INCOMING[cnt];
r2[cnt] = ~SBF[grp][i][cnt] & INCOMING[cnt];
r3[cnt] = SBF[grp][i][cnt] & ~INCOMING[cnt];
cnt--;
}
m11 = ( char*)r1;
m01 = ( char*)r2;
m10 = ( char*)r3;
for (m = SBF_LEN * sizeof( char); m--;
j11 += NumberOfSetBits(*m11++),
j01 += NumberOfSetBits(*m01++),
j10 += NumberOfSetBits(*m10++));
jacc_sim = j11 / (float)(j11 + j01 + j10);
if (jacc_sim < SIM_THRESHOLD);
//continue;//do nothing
else
{
jacc_sim_rec[j] = jacc_sim;//keep record of similarity
++j;//record number of highly similar elements
}
}
}
I don't understand the code, but I'll bet the problem is that you're not reinitializing cnt each time through the for loop, so you only fill in r1, r2, and r3 when i = 0.
Change that loop to:
for (int cnt = SBF_LEN - 1; cnt >= 0; cnt--)
{
r1[cnt] = SBF[grp][i][cnt] & INCOMING[cnt];
r2[cnt] = ~SBF[grp][i][cnt] & INCOMING[cnt];
r3[cnt] = SBF[grp][i][cnt] & ~INCOMING[cnt];
}
I'm also not sure why this needs to count down instead of up, like a typical loop, but it shouldn't make a difference.

Array Indexes incorrectly when reading input from file

I'm trying to read comma separated data from a line from a .txt file and then parse the data into 2 different arrays (names & indScores). From the indScores[], I'm getting the overall average for a particular name and storing that into my avg_scores[]. Then at the very end, return total lines that were read.
Sample input data looks like this:
name1,x1,x2,x3,x4,x5
name2,y1,y2,y3,y4,y5
name3,z1,z2,z3,z4,z5
name4,a1,a2,a3,a4,a5
....
My arrays output this
names[name2, name4, name6, name8,...]
avg_scores[x_avg, x_avg + y_avg, x_avg + y_avg + z_avg,...]
And my overall line count is half of what I'm expecting. Am I indexing at the wrong position or is my logic wrong?
int ReadScores(string fileName, string names[], float avg_scores[], int array_size){
float indScores[array_size];
int lineCounter = 0;
string myLine, nameSubString, scoreSubString;
float scoreConvert = 0.0;
float averageScores = 0.0;
ifstream myFileIn;
//open the file
myFileIn.open(fileName, ios::in);
if (myFileIn.fail()){
cout << "Error opening "<< fileName << endl;
return 0;
}
int index = 0;
//read the file with a while loop until the end of file is reached
while (getline(myFileIn, myLine)){
averageScores;
getline(myFileIn, myLine);
//firstComma will hold the integer value of the index position of the first comma found
int firstComma = myLine.find(',');
//this should grab the the names at the beginning of each string on each new line
nameSubString = myLine.substr(0, firstComma);
names[index] = nameSubString;
int startingPos = 0;
float commaCounter = 0;
//find how many commas are in a string and use that to limit your loop
for (int ind = 0; ind < myLine.length(); ind++){
if (myLine[ind] == ',')
commaCounter++;
}
for (int ind = 0; ind < commaCounter; ind++){
//grab the first number and store it the scoreSubString variable
//this tells the myLine.substr to start after the very first comma
int found = myLine.find(',', firstComma) + 1;
scoreSubString = myLine.substr(found, myLine.find(','));
//change the value of firstComma to the next index location
firstComma = found + 1;
///convert string to number
stringstream(scoreSubString) >> scoreConvert;
///store number in float array
indScores[ind] = scoreConvert;
}
for (int ind = 0; ind < commaCounter; ind++){
averageScores = indScores[ind] + averageScores;
}
float averageOverall = averageScores/commaCounter;
//store the averageOverall into the avg_scores []
avg_scores[index] = averageOverall;
index++;
lineCounter++;
}
myFileIn.close();
return lineCounter;
}
Right, once I deleted that second getline(myFilenIn, myLine) things started to match up.
I also needed to reset my averageScores = 0 before the for loop that was getting my averageScores and add a starting position found for my .find(',', found), without it I was constantly starting from the beginning.
My new code looks like this:
int ReadScores(string fileName, string names[], float avg_scores[], int array_size){
int linesCounted = 0;
float indScores[array_size];
int lineCounter = 0;
string myLine, nameSubString, scoreSubString;
float scoreConvert = 0.0;
float averageScores = 0.0;
ifstream myFileIn;
//open the file
myFileIn.open(fileName, ios::in);
if (myFileIn.fail()){
cout << "Error opening "<< fileName << endl;
return 0;
}
int index = 0;
//read the file until the end of file is reached
while (getline(myFileIn, myLine)){
//firstComma will hold the integer value of the index position of the first comma found
int firstComma = myLine.find(',');
//this should grab the the names at the beginning of each string on each new line
nameSubString = myLine.substr(0, firstComma);
names[index] = nameSubString;
int startingPos = 0;
float commaCounter = 0;
//find how many commas are in a string and use that to limit your loop
for (int ind = 0; ind < myLine.length(); ind++){
if (myLine[ind] == ',')
commaCounter++;
}
for (int ind = 0; ind < commaCounter; ind++){
//grab the first number and store it the scoreSubString variable
int found = myLine.find(',', firstComma) + 1;
scoreSubString = myLine.substr(found, myLine.find(',', found));
//change the value of firstComma to the next index location
firstComma = found + 1;
///convert string to number
stringstream(scoreSubString) >> scoreConvert;
///store number in float array
indScores[ind] = scoreConvert;
}
averageScores = 0;
for (int ind = 0; ind < commaCounter; ind++){
averageScores = indScores[ind] + averageScores;
}
float averageOverall = averageScores/commaCounter;
avg_scores[index] = averageOverall;
index++;
if (!myLine.empty()){
lineCounter++;
}
}
myFileIn.close();
return lineCounter;
}

Connect-N Board Game, crashing when Width is >> Height

I'm in the process of coding a Connect-N board game, and I'm almost finished and have gone through troubleshooting. My problem is now after changing some stuff my game crashes when the computer plays its move if the Width is too much greater than the height. There are two functions involved here, so I will paste them both.
Board
*AllocateBoard(int columns, int rows)
{
int **array= malloc(sizeof(int *) *columns);
int r = 0;
for ( r = 0; r < columns; ++r)
{
array[r] = malloc(sizeof(int) * rows);
}
int j = columns - 1;
int k = rows - 1;
int m = 0;
int n = 0;
for ( m = 0; m < j; ++m)
{
for ( n = 0; n < k; ++n)
{
array[m][n] = 0;
}
}
Board *board = malloc(sizeof(Board));
board->columns = columns;
board->rows = rows;
board->spaces = array;
return board;
}
This first function allocates the board to be a matrix Width * Height that the user passes in via the command line. It then initializes every space on the board to be zero, and then stores the columns, rows, and spaces into a Board structure that I've created. It then returns the board.
int
computerMakeMove(Board *board)
{ int RandIndex = 0;
int **spaces = board->spaces;
int columns = board->columns;
int *arrayoflegalmoves = malloc(sizeof(int) * (columns));
int columncheck = 0;
int legalmoveindex = 0;
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
}
if (legalmoveindex == 1)
{
return arrayoflegalmoves[0];
}
else
{
RandIndex = rand() % (legalmoveindex);
return arrayoflegalmoves[RandIndex];
}
}
This second function is designed to make the computer randomly pick a column on the board. It does this by checking the value of the top row in each column. If there is a zero there, it will store this value in an array of legal moves, and then it increments the legalmoveindex. If there isn't, it skips the column and checks the next. It ends when it gets finished checking the final column. If there is only one legal move, it will play it. If there are more, it will select a random index from the array of legal moves (I run srand in the main) and then return that value. It will only ever attempt to play on a legal board, so that's not the problem. I am pretty confident the problem occurs in this function, however, as I call the functions as follows
printf("Taking the computers move.\n");
{printf("Taking computer's move.");
computermove = computerMakeMove(playerboard);
printf("Computer's move successfully taken.\n");
playerboard = MakeMove(playerboard, computermove, player);
printf("Computer's board piece successfully played.\n");
system("clear");
displayBoard(playerboard);
...;
}
and it prints
Aborted (core dumped)
immediately after it prints
"Taking computer's move."
Once again, my question is: why is my program crashing if the width is larger than the height when the computer plays?
Thanks.
Edit: I found the solution and I am stupid.
I realloc'd during the while loop.
The realloc should be the first thing outside of the while loop.
The answer for any future programmers who may have this problem:
Notice the
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
}
has a realloc inside of it. The realloc should be moved to immediately outside of it, like so
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
it is unusual to have the columns be the first index in an array.
having the first index of an array be columns leads to confusion
// suggest using camel case for all variable names, for readability
Board *AllocateBoard(int columns, int rows)
{
int **array= malloc(sizeof(int *) *columns); // add check that malloc successful
int r = 0;
for ( r = 0; r < columns; ++r)
{
array[r] = malloc(sizeof(int) * rows); // <-- add: check that malloc successful
}
int j = columns - 1; // this results in last column not initialized
int k = rows - 1; // this results in last row of each column not initialized
int m = 0; // column loop counter
int n = 0; // row loop counter
for ( m = 0; m < j; ++m)
{
for ( n = 0; n < k; ++n)
{
array[m][n] = 0;
}
}
Board *board = malloc(sizeof(Board)); // <-- add: check if malloc successful
board->columns = columns;
board->rows = rows;
board->spaces = array;
return board;
} // end function: AllocateBoard
// why is this only looking at the first row of each column?
int computerMakeMove(Board *board)
{
int RandIndex = 0;
int **spaces = board->spaces;
int columns = board->columns;
int *arrayoflegalmoves = malloc(sizeof(int) * (columns)); // <-- add check that malloc successful
int columncheck = 0;
int legalmoveindex = 0;
while (columncheck <= columns - 1)// should be: for(; columncheck < columns; columncheck++ )
{
if (spaces[columncheck][0] == 0)
{ // then first row of column is zero
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck; // <-- remove this line
}
else // remove this 'else' code block
{
++columncheck;
} // end if
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
// <-- 1) use temp int*, in case realloc fails
// <-- 2) if realloc successful, update arrayoflegalmoves
// <-- 3) the code is not checking each row of each column,
// so the original malloc is more than plenty
// so why bother to realloc
// <-- 4) if legalmoveindex is 0 then realloc returns NULL
} // end while
// in following, what about when zero moves found? probably should return NULL
if (legalmoveindex == 1)
{ // only one column[row0] found to contain 0
return arrayoflegalmoves[0];
}
else
{
RandIndex = rand() % (legalmoveindex);
return arrayoflegalmoves[RandIndex]; // if zero moves found, this returns a
// de-reference to address 0
// which would result in a seg fault event
} // end if
} // end function: computerMakeMove

C: Why am I getting 'Floating Point Exception: 8' From This Calculation?

Here is my function:
int scoreString(char *toScore) {
int length = strlen(toScore);
int score = 0;
int spaceCount = 0;
for (int i = 0; i < length; i++) {
char current = toScore[i];
if (current == ' ') {
spaceCount++;
}
score += scoreChar(current);
}
//English words are ~5 characters
int charsPerWord = (length/(spaceCount + 1));
if (charsPerWord >=3 && charsPerWord <= 7) {
//Big Bonus
score = score * 2; //THIS LINE CAUSES PROBLEMS
} else if (spaceCount <= 1) {
//Big penalty
score = score / 2; //THIS LINE CAUSES PROBLEMS
}
return score;
}
If I get ride of the two lines that are marked as causing problems, everything is dandy. The output of this function without them ranges from 100-2000 on the input I'm testing so this should not be an overflow error ... if I leave either of those two lines in I get Floating point exception: 8 after a few executions. Any ideas?

jCombobox giving incremental value error on jTable

I am having problems with my code below, the code below shows a jComboBox being populated, when i select an item from this list it is added to the jTable below it.
There is alos code to check for duplicate entries ont he table. If a duplicate entry is found it should increase the qty column by one and not create a seperate entry.
This is where the problem comes in, when I press the back button on this screen and go to a different screen and then come back via same route as the first time, I get an incrementally different qty added to the table row/cell.
I have also included the code that populates the Round Details depending on Round Drop selected from table, for reference, but Im fairly certain the problem lies in the below code. The navigation is as follows...
To get to the below screen... Round Drop panel table of round drops) >> click on table row and taken to associated round details panel >> pressing the Till button takes user to screen with code below...
Test results:
First pass through below code using navigation above gives results as expected
Second pass gives an initial value of 2 (instead of one), and duplicate row increases qty by 2 instead of one
Third pass gives an initial value of 3 (instead of one), and duplicate row increases qty by 3 instead of one
Fourth pass gives an initial value of 4 (instead of one), and duplicate row increases qty by 4 instead of one
...and so on.
Any help, guidance on solution or a better design would be hugely appreciated.
Thanks
/*************Code sample ********************************/
public void tillOperations(String sourceCall) {
final DefaultTableModel model = (DefaultTableModel)main.tillPanel.tblTillSale.getModel();
if (main.tillPanel.cmbTillProdSelect.getItemCount() < 1) {
for (int d = 0; d < roundStockObj.length ; d++) {
main.tillPanel.cmbTillProdSelect.addItem(roundStockObj[d].getDescription());
}}
main.tillPanel.tblTillSale.removeRowSelectionInterval(0, model.getRowCount() - 1);
main.tillPanel.cmbTillProdSelect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent f)
{
int qty = 1;
for (int index = 0; index < 4; index++) {
addSelectedItem[index] = "";
}
int row;
selectedItem = null;
main.tillPanel.tblTillSale.removeRowSelectionInterval(0, model.getRowCount() - 1);
selectedItem = main.tillPanel.cmbTillProdSelect.getSelectedItem();
for (int d = 0; d < roundStockObj.length; d++) {
if (selectedItem.equals(roundStockObj[d].getDescription())) {
addSelectedItem[0] = roundStockObj[d].getDescription();
addSelectedItem[1] = Integer.toString(qty);
addSelectedItem[2] = Double.toString(roundStockObj[d].getPrice()).trim();
addSelectedItem[3] = Double.toString(roundStockObj[d].getPrice()).trim();
//break;
}
}
if(model.getRowCount() == 0) { //check if model is empty
model.addRow(new String[]{addSelectedItem[0], addSelectedItem[1], addSelectedItem[2], addSelectedItem[3]});
}
else { //check if there is a duplicate row
int duplicateRow = -1;
for (row = 0 ; row < model.getRowCount(); row++) {
if(addSelectedItem[0].equals(main.tillPanel.tblTillSale.getModel().getValueAt(row,0))) {
duplicateRow = row;
break;
}
}
if(duplicateRow == -1) { //if there is no duplicate row, append
model.addRow(new String[]{addSelectedItem[0], addSelectedItem[1], addSelectedItem[2], addSelectedItem[3]});
}
else { //if there is a duplicate row, update
main.tillPanel.jLabel1.setText(addSelectedItem[1]);
DecimalFormat fmtObj = new DecimalFormat("####0.00");
int currentValue = Integer.parseInt(main.tillPanel.tblTillSale.getValueAt(row, 1).toString().trim());
int newValue = currentValue + 1;
Integer newValueInt = new Integer(newValue);
model.setValueAt(newValueInt, row, 1);
double unitPrice = Double.parseDouble(main.tillPanel.tblTillSale.getValueAt(row, 2).toString().trim());
double newPrice = newValue * unitPrice;
Double newPriceDbl = new Double(newPrice);
main.tillPanel.tblTillSale.setValueAt(fmtObj.format(newPriceDbl), row, 3);
}
}
main.tillPanel.tblTillSale.removeRowSelectionInterval(0, model.getRowCount() - 1);
for (int index = 0; index < 4; index++) {
addSelectedItem[index] = "";
}
}
});
//This code loads the specific Round Details, based on the selection form the round drops table
public void displayRoundDropDetails() {
DefaultTableModel model = (DefaultTableModel)main.selectRoundDropPanel.tblSelectRoundDrop.getModel();
if (!loaded) {
for (int d = 0; d < roundDropsData.length; d++) {
if (roundDropsData[d][0].equals(defaultRoundID)) {
model.addRow(new Object[]{roundDropsData[d][3], roundDropsData[d][2],
roundDropsData[d][4], roundDropsData[d][5]});
}
}
loaded = true;
}
main.selectRoundDropPanel.tblSelectRoundDrop.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
int row = 0;
row = main.selectRoundDropPanel.tblSelectRoundDrop.getSelectedRow();
for (int index = 0; index < roundDropsData.length; index++) {
if (roundDropsData[index][3].equals(
main.selectRoundDropPanel.tblSelectRoundDrop.getModel().getValueAt(row, 0))) {
main.roundDetailsPanel.txtRoundDetailsAddress.setText(roundDropsData[index][6] + "\n"
+ roundDropsData[index][7] + ", " + roundDropsData[index][8] + "\n" +
roundDropsData[index][9]);
main.roundDetailsPanel.lblRoundDetailsName.setText(roundDropsData[index][2]);
main.roundDetailsPanel.txtRoundDetailsInstuct.setText(roundDropsData[index][10]);
main.roundDetailsPanel.txtDropDetailsIn.setText(roundDropsData[index][4]);
main.roundDetailsPanel.txtDropDetailsOut.setText(roundDropsData[index][5]);
main.roundDetailsPanel.txtRoundDetailsInstruct.setText(roundDropsData[index][12]);
break;
}
}
Globals.CURRENT_COMPONENT = "selectRoundDropPanel";
showRoundDetailsPanel();
}
});
}
Try changing the listener for JComboBox. try using stateChangeListener.

Resources