Creating Daily and Minutely MA - Practical Assignment

Feel free to ask questions here if you have issue with this assignment.

1 Like

First to blog!!! Done it and loving the whole training course!!!

2 Likes

Hi Guys,

Everything seems to work well when executing only one Moving Averages at a time.

On the other hand, when trying to request results from the three MA’s together at the same time the terminal always gives following error on the first module.exports in the indicators file.

So when I put minutely MA first in the file:

TypeError: indicators.minutelyMovingAverage is not a function
at Object.<anonymous> (/Users/jebeljohm/Documents/Crypto/Ivan Programming/Tradingbots/index.js:14:12)

When I put hourly MA first in the file:

TypeError: indicators.hourlyMovingAverage is not a function
at Object.<anonymous> (/Users/jebeljohm/Documents/Crypto/Ivan Programming/Tradingbots/index.js:18:12)

1 Like

How do you get more than 31 days of historical data using the histoDay function.

I am unable to figure that out.

I think it might be the fact that there has to be a comma between the functions under module.exports in the indicators.js file.

3 Likes

Hi Inus, correct! I did three seperate exports modules, that’s why it didn’t work.
Thanks a lot :grinning:!!

Hello Ivan - loving the course!

I need some help with syntax for the limit option using histoHour - I want to change the default of 30 days to ‘none’ but can’t get it right. Everything is working correctly otherwise.

PS C:\Users\Ken\Desktop\Code> node index.js
HourlyMA: 142.80959999999993
DailyMA: 136.92
MinutleyMA: 141.9838

//with days > 31
PS C:\Users\Ken\Desktop\Code> node index.js
HourlyMA: 142.81319999999994
TypeError: Cannot read property ‘close’ of undefined
at CryptoCompareAPI.histoDay.then.data (C:\Users\Ken\Desktop\Code\indicators.js:69:18)
at process._tickCallback (internal/process/next_tick.js:68:7)
MinutleyMA: 141.984

Please post your code here, thanks

I think that I have it working right. Now dailyMovingAverage is available for up to 365 days.

PS C:\Users\Ken\Desktop\Code> node index.js
HourlyMA: 142.83179999999996
MinutleyMA: 142.0304
DailyMA: 136.26

from node.js
indicators.minutelyMovingAverage(“ETH”,“USD”,50,function(result){
console.log("MinutleyMA: ", result)}),
indicators.hourlyMovingAverage(“ETH”,“USD”,50,function(result){
console.log("HourlyMA: ", result)}),
indicators.dailyMovingAverage(“ETH”,“USD”,50,function(result){
console.log("DailyMA: ", result)});

from indicators.js:
const CCAPIKey = “b5c65d6a8e240b7faec31b7243234c445eda6fa6a1c65382520c0ccdc7c95f5e”
const CryptoCompareAPI = require(“cryptocompare”);
CryptoCompareAPI.setApiKey(CCAPIKey);

module.exports = {
minutelyMovingAverage:function(cryptoAsset,fiatCurrency,minutes,callback){

  if(minutes>1440){
    console.error("Only up to 1440 minutes allowed!")
    return
  }

// 1 get data from CryptoCompare
CryptoCompareAPI.histoMinute(cryptoAsset, fiatCurrency)
.then(data => {
  // 2 calculate MA from past minutes
  data = data.reverse()
  var sum = 0;
  for(var i = 0;i<minutes;i++){
    sum+=data[i].close;
  }

  var movingAverage = sum/minutes;
  callback(movingAverage);

})
.catch(console.error)

},

hourlyMovingAverage:function(cryptoAsset,fiatCurrency,hours,callback){

if(hours>169){
  console.error("Only up to 169 hours allowed!")
  return

}

// 1 get data from CryptoCompare
CryptoCompareAPI.histoHour(cryptoAsset, fiatCurrency)
.then(data => {
// 2 calculate MA from past hours
data = data.reverse()
var sum = 0;
for(var i = 0;i<hours;i++){
sum+=data[i].close;
}

  var movingAverage = sum/hours;
  callback(movingAverage);

})
.catch(console.error)

},

dailyMovingAverage:function(cryptoAsset,fiatCurrency,days,callback){

if(days>365){
  console.error("Only up to 365 days allowed!")
  return

}

// 1 get data from CryptoCompare
CryptoCompareAPI.histoDay(cryptoAsset, fiatCurrency,{‘limit’:‘none’})
.then(data => {
// 2 calculate MA from past days
data = data.reverse()
var sum = 0;
for(var i = 0;i<days;i++){
sum+=data[i].close;
}

var movingAverage = sum/days;
callback(movingAverage);

})
.catch(console.error)
}
}

1 Like

My solution :

// indicators.js

const Logger = require("./logger.js");
const CryptoCompareApiKey = "12b23e55426ae7d2aa024ce96a131e2026e9ae3ef2131ba60474e2bd89eba46d";
const CryptoCompareAPI = require("cryptocompare");
CryptoCompareAPI.setApiKey(CryptoCompareApiKey);

module.exports = 
{
	DailyMovingAverageAsync: 
		async function DailyMovingAverageAsync(
			cryptoAsset,
			currency,
			hours,
			currentElementIndex)
		{
			const priceHistory =
			 	await CryptoCompareAPI.histoDay(
			 			cryptoAsset, 
			 			currency
			 	   ,{
			 			limit : hours + currentElementIndex + 1
			 		}
			 	);

			const priceHistoryToPast = priceHistory.reverse();

			const nowMovingAverage =
				CalculateMovingAverageByClosingPriceForItem(
					priceHistoryToPast,
					/*currentElementIndex:*/ currentElementIndex,
					/*windowSize:*/ hours
				);

			return nowMovingAverage;
		}



	, HourlyMovingAverageAsync: 
		async function HourlyMovingAverageAsync(
			cryptoAsset,
			currency,
			hours,
			currentElementIndex)
		{
			const priceHistory =
			 	await CryptoCompareAPI.histoHour(
			 			cryptoAsset, 
			 			currency
			 	   ,{
			 			limit : hours + currentElementIndex + 1
			 		}
			 	);

			const priceHistoryToPast = priceHistory.reverse();

			const nowMovingAverage =
				CalculateMovingAverageByClosingPriceForItem(
					priceHistoryToPast,
					/*currentElementIndex:*/ currentElementIndex,
					/*windowSize:*/ hours
				);

			return nowMovingAverage;
		}


	, MinutelyMovingAverageAsync: 
		async function MinutelyMovingAverageAsync(
			cryptoAsset,
			currency,
			hours,
			currentElementIndex)
		{
			const priceHistory =
			 	await CryptoCompareAPI.histoMinute(
			 			cryptoAsset, 
			 			currency
			 	   ,{
			 			limit : hours + currentElementIndex + 1
			 		}
			 	);

			const priceHistoryToPast = priceHistory.reverse();

			const nowMovingAverage =
				CalculateMovingAverageByClosingPriceForItem(
					priceHistoryToPast,
					/*currentElementIndex:*/ currentElementIndex,
					/*windowSize:*/ hours
				);

			return nowMovingAverage;
		}

}


function JsonBeautifyDefault(json)
{
	const result = 
		JsonBeautify(
			/*value:*/ json,
			/*replacer:*/ null,
			/*space:*/ 2,
			/*limit:*/ 80
		);

	return result;
}




function CalculateMovingAverageByClosingPriceForItem(
	priceHistoryToPast, 
	currentElementIndex, 
	windowSize)
{
	var result = 0;
	var accumulatedSum = 0;

	for (i = 0; i < windowSize; i++)
	{
		accumulatedSum += priceHistoryToPast[currentElementIndex + i].close;
	}

	result = accumulatedSum / windowSize;

	return result;
}


// usage

const DEFAULT_WINDOW_SIZE = 100;


async function MovingAverageIndicatorsLogicAsync()
{
	var nowMovingAverageDay =
	await Indicators.DailyMovingAverageAsync(
		/*cryptoAsset:*/ "BTC",
		/*currency:*/ "USD",
		/*hours:*/ DEFAULT_WINDOW_SIZE,
		/*currentElementIndex:*/ 0
	);

	console.log('daily 100 nowMovingAverage : ' + nowMovingAverageDay);

	var nowMovingAverageHour =
	await Indicators.HourlyMovingAverageAsync(
		/*cryptoAsset:*/ "BTC",
		/*currency:*/ "USD",
		/*hours:*/ DEFAULT_WINDOW_SIZE,
		/*currentElementIndex:*/ 0
	);

	console.log('hourly 100 nowMovingAverage : ' + nowMovingAverageHour);

	var nowMovingAverageMinute =
	await Indicators.MinutelyMovingAverageAsync(
		/*cryptoAsset:*/ "BTC",
		/*currency:*/ "USD",
		/*hours:*/ DEFAULT_WINDOW_SIZE,
		/*currentElementIndex:*/ 0
	);

	console.log('minutely 100 nowMovingAverage : ' + nowMovingAverageMinute);

}


main( MovingAverageIndicatorsLogicAsync );

Ok this is doing my life in…

@ivan i tried doing my own code for it copying what we learnt in the hourly MA… Which is:

const CCAPIKey = "7cf6ac539f5b54f35c90798aee4b4957800026fac6de2eb1971d6879b8d12cc9";
const CryptoCompareAPI = require("cryptocompare");
CryptoCompareAPI.setApiKey(CCAPIKey);

module.exports = {

hourlyMovingAverage:function(cryptoAsset, fiatCurrency, hours, callback){

  if(hours>169){
    console.error("Only up to 169 hours allowed")
    return
  }



  CryptoCompareAPI.histoHour(cryptoAsset, fiatCurrency)

  .then(data => {
    data = data.reverse()
      var sum = 0;
      for(var i = 0;i<hours;i++){
      sum +=data[i].close;
    }
    var movingAverage = sum/hours;
    callback(movingAverage);
  })
  .catch(console.error);



},



dailyMovingAverage:function(cryptoAsset, fiatCurrency, days, callback){

  if(days>365){
    console.error("Only up to 365 days allowed")
    return




  CryptoCompareAPI.histoDay(cryptoAsset, fiatCurrency)

  .then(data => {
    data = data.reverse()
      var sum = 0;
      for(var i = 0;i<days;i++){
      sum +=data[i].close;
    }
    var movingAverage = sum/days;
    callback(movingAverage);
  })
  .catch(console.error);

  }

}
}

I run that and i get PS C:\Users\Russ1\Desktop\Coding Stuffs\Trading bot> node index.js
Hourly Moving Average is: 5777.275600000001

It wont show the daily, its like its not getting the data??

I tried using @kjames code for the daily and i get the error:

TypeError: Cannot read property ‘close’ of undefined
at CryptoCompareAPI.histoDay.then.data (C:\Users\Russ1\Desktop\Coding Stuffs\Trading bot\indicators.js:77:14)
at process._tickCallback (internal/process/next_tick.js:68:7)
Hourly Moving Average is: 5777.2773

  indicators.hourlyMovingAverage("BTC","USD",100,function(result){
    console.log("Hourly Moving Average is: ", result)
  }),

  indicators.dailyMovingAverage("BTC","USD",365,function(result){
    console.log("Daily Moving Average is: ", result)
  });

index.js file indicator calls look like this

Ok so i worked out the difference in code, i had a } in the wrong spot.

However now i get the :

TypeError: Cannot read property 'close' of undefined
   at CryptoCompareAPI.histoDay.then.data (C:\Users\Russ1\Desktop\Coding Stuffs\Trading bot\indicators.js:43:21)
   at process._tickCallback (internal/process/next_tick.js:68:7)

try with:

CryptoCompareAPI.histoDay(cryptoAsset, fiatCurrency, {limit:“none”})

1 Like

I noticed that in the comments above and finally got it to work haha :hugs::hugs:

Does anyone know how to do a setup to go 100% each trade?

return restClient.newOrder({amount:0.5,
price:50000,
side:“buy”,
symbol:“btcusd”,
options:[“immediate-or-cancel”]})

Now each buy trade goes 0.5 BTC but I want to do it 100%…

@ivan

My results:
PS C:\Users\power\Desktop\Ivan Course Programming\Gemini Trading Bot> node index.js
Hourly MA: 9307.641
Minute MA: 9357.5772
Daily MA: 9593.805300000002

Here are from index.js:

indicators.hourlyMovingAverage(“BTC” , “USD” , 100 , function(result){
console.log("Hourly MA: " , result)
}),

indicators.dailyMovingAverage(“BTC” , “USD” , 100 , function(result){
console.log("Daily MA: " , result)
}),

indicators.minuteMovingAverage(“BTC” , “USD” , 100 , function(result){
console.log("Minute MA: " , result)
});


And from indicators.js:

module.exports = {

hourlyMovingAverage : function(cryptoAsset , fiatCurrency , hours , callback){
if(hours > 169){
console.error(“Only up to 169 hours allowed!”)
return
}
// Print MA of the last 100 hours close price going backwards from now
CryptoCompareApi.histoHour(cryptoAsset, fiatCurrency)
.then(data => {
data = data.reverse()
var sum = 0;
for(var i = 0; i < hours; i++){
sum += data[i].close;
}
var movingAverage = sum / hours;
callback(movingAverage);
})
.catch(console.error)
},

dailyMovingAverage : function(cryptoAsset , fiatCurrency , days , callback){
if(days > 365){
console.error(“Only up to 365 days allowed!”)
return
}
// Print MA of the last 100 hours close price going backwards from now
CryptoCompareApi.histoDay(cryptoAsset, fiatCurrency , {limit:“none”})
.then(data => {
data = data.reverse()
var sum = 0;
for(var i = 0; i < days; i++){
sum += data[i].close;
}
var movingAverage = sum / days;
callback(movingAverage);
})
.catch(console.error)
},

minuteMovingAverage : function(cryptoAsset , fiatCurrency , minutes , callback){
if(minutes > 1440){
console.error(“Only up to 1440 minutes allowed!”)
return
}
// Print MA of the last 100 hours close price going backwards from now
CryptoCompareApi.histoMinute(cryptoAsset, fiatCurrency)
.then(data => {
data = data.reverse()
var sum = 0;
for(var i = 0; i < minutes; i++){
sum += data[i].close;
}
var movingAverage = sum / minutes;
callback(movingAverage);
})
.catch(console.error)
}

}

Last exercise. … My try is to check more shorter time periods and as Ivan said in the end - find a way to buy more when the price starts to go up. At the moment, since I could not advance for technical reasons, I am reading other peoples solutions and trying to learn form them.

Let’s build daily and minutely indicators!

In principle this task was not too difficult since you only had to change certain expressions. I will explain how to get from the hourlyMovingAverage to the minutelyMovingAverage function:

1.)
hourlyMovingAverage:function(cryptoAsset, fiatCurrency, hours, callback){

to

minutelyMovingAverage:function(cryptoAsset, fiatCurrency, minutes, callback){

(hourlyMovingAverage to minutelyMovingAverage and hours to minutes)

2.)
CryptoCompareAPI.histoHour(cryptoAsset, fiatCurrency)

to

CryptoCompareAPI.histoMinute(cryptoAsset, fiatCurrency)

(histoHour to histoMinute)

3.)
if (hours>169) {
console.error(“Only up to 169 hours allowed!”);
return

to

if (minutes>1441) {
console.error(“Only up to 1441 minutes allowed!”);
return

(hours to minutes and 169 to 1441)

4.)

for (var i=0; i<hours; i++){

to

for (var i=0; i<minutes; i++){

(hours to minutes)

5.)
var movingAverage = sum / hours;

to

var movingAverage = sum / minutes;

(hours to minutes)

Another thing that should not be forgotten is the comma behind the first and the second function after the last curly bracket of these functions. Since the third function is the last one at the moment there must not be a comma after the last curly bracket of this function.

Finding out about the index boundaries

I used the following temporary code in each function before the callback to find out the index boundaries:

console.log(data.length);

This gave me the following results:

169
daily MA:  7112.343250000001
169
hourly MA:  7118.710700000001
1441
minutely MA:  6843.309819819822

This method is more reliable than to look for this information in the API documentation, because for the API call histoDay a default value of 30 is documented, which is not updated to the current actual value of 169 yet. Increasing the index just by one each function will run into an error!

In the following the full code of the module indicators.js is shown:

const CryptoCompareAPI = require("cryptocompare");
const CCAPIKey="6f48b0b8ec36e174dff6a4cc1550ab55afc12208c50784300d515d6e5f2dc7d5"
CryptoCompareAPI.SetApiKey = CCAPIKey;

module.exports = {

  minutelyMovingAverage:function(cryptoAsset, fiatCurrency, minutes, callback){
    if (minutes>1441) {
      console.error("Only up to 1441 minutes allowed!");
      return
    }
    CryptoCompareAPI.histoMinute(cryptoAsset, fiatCurrency)
    .then(data => {
      data = data.reverse();
      var sum = 0;
      for (var i=0; i<minutes; i++){
        sum += data[i].close;
      }
      var movingAverage = sum / minutes;
      callback(movingAverage);
    })
    .catch(console.error)
  },

  hourlyMovingAverage:function(cryptoAsset, fiatCurrency, hours, callback){
    if (hours>169) {
      console.error("Only up to 169 hours allowed!");
      return
    }
    CryptoCompareAPI.histoHour(cryptoAsset, fiatCurrency)
    .then(data => {
      data = data.reverse();
      var sum = 0;
      for (var i=0; i<hours; i++){
        sum += data[i].close;
      }
      var movingAverage = sum / hours;
      callback(movingAverage);
    })
    .catch(console.error)
  },

  dailyMovingAverage:function(cryptoAsset, fiatCurrency, days, callback){
    if (days>169) {
      console.error("Only up to 169 days allowed!");
      return
    }
    CryptoCompareAPI.histoHour(cryptoAsset, fiatCurrency)
    .then(data => {
      data = data.reverse();
      var sum = 0;
      for (var i=0; i<days; i++){
        sum += data[i].close;
      }
      var movingAverage = sum / days;
      callback(movingAverage);
    })
    .catch(console.error)
  }

}

Please note that the code will not work with the API provided above since I have deleted this API key. Please create and use your own Cryptocompare API Key.

I used the following calls to test the three functions:

// 100 minutes Moving Average
indicators.minutelyMovingAverage("BTC", "USD", 100, function(result){
  console.log("minutely MA: ", result);
});

// 100 hour Moving Average
indicators.hourlyMovingAverage("BTC", "USD", 100, function(result){
  console.log("hourly MA: ", result);
});

// 100 day Moving Average
indicators.dailyMovingAverage("BTC", "USD", 100, function(result){
  console.log("daily MA: ", result);
});

This resulted in the following reply:

hourly MA:  7117.136800000002
daily MA:  7117.206200000002
minutely MA:  6862.9628999999985

The construction of the function dailyMovingAverage works in an analogous way. Please always try to do the assignments on your own. Running into problems and figuring out why it is not working at the moment is a very important task learning and getting used to a new programming language.

5 Likes

As I earlier said I have to go through this course again, have to learn Java programming. Reading the other peoples solutions and trying to learn from them.