About my change from a programmer to a "post leek zero" [node realizes e-mail sending]

1, Previously on

I know a friend who made 380000 Yuan in just one month. I asked him how he earned it. He said that he recommended the stock limit to others. He was interrupted by someone and the other party lost... ⊙﹏⊙∥

   the above is a passage. Don't take it seriously, As a "chive zero generation" ("chive years"), a very qualified chive, I have experienced the soaring during the epidemic period and the sharp decline last year (2020). Zhonggai Internet, which I bought at the beginning of last year, is still in hand, and has achieved the goal of "common prosperity" from a certain point of view, Really, the more you make up, the more you fall, the more you make up! I just don't sell, as long as I don't sell, I won't lose! Convex ('△´ +) has the ability to liquidate! (` へ´ *) ノ (the front is full of angry words. I'm kidding. Don't liquidate. I'm still waiting for my return ゝ)

   after a year of "falling and falling" last year, I decided to start intelligent fixed investment. Finally, with my unremitting efforts, I finally ushered in! The smile curve (* ~ ^^^^^^^^^^^^^^^^^^^6534. Therefore, I have always had an idea in my mind, that is, to select several "chickens" and then observe the daily rise and fall of valuation to decide to buy and sell, but it is impossible to stare at them every day! Therefore, I decided to use the advantages of my small front-end to realize this simple demand of 100 million points, just to complete the node e-mail sending demand that I wrote last time. Therefore, I used e-mail to subscribe to the rise and fall of "chicken essence" every day. I don't have much nonsense. Let's start preparing!

2, "Trading" preparation

   before writing the code, you must first clarify the needs. My needs are very simple, that is, subscribe to some funds, monitor their valuations every day, and inform me by email if you meet the conditions for rise and fall. Therefore, abstract the data, which is a list of funds, regularly traverse their valuations every day, and finally filter out the qualified funds and inform me by email.

   when the requirements are clarified, we should pay attention to the input and output. The output is very simple, that is, the qualified data will be informed to me through e-mail, while the input needs some online open interfaces to obtain the data I need through the interface.

  1. So the first step is to search the API (Interface) of fund related information. Here I found a blog Daily fund Of course, powerful leaders can directly go to some fund related websites to obtain the data interface, which is also very simple ( ̄▽  ̄) و.
  2. The second step is to select a language. As a small front end, node must be used to achieve the target requirements. Of course, selecting a language alone is certainly not enough. It also needs toolkits issued by various bosses, otherwise it will be very tired to make wheels by hand (except for real bosses).
  3. The third step is to find the toolkit. The first is the function of sending mail. Because the smtp service of mailbox is used, nodemailer and nodemailer smtp transport are used here, and then the related requests are processed. axios is used here. Finally, the subscription information needs to be sent regularly. Node schedule is used for the timer here.
  4. Step 4: open VsCode and start writing code. (what? You said you didn't use VsCode!!! ∑ (゚) Д ゚ノノノノノノノノノノノノノノノノノノ. Of course, you can use a familiar editor. I prefer VsCode here)

To sum up, we use four npm packages: nodemailer, nodemailer SMTP transport, axios, and node schedule.

3, Implementation of "trading assistant"

   the requirements here can be divided into two parts: e-mail sending and fund information acquisition. Therefore, the codes of these two parts can be extracted and written in two files, focusing only on the requirements realization of the same functional module (decoupling and aggregation in business logic). The document structure of the project is as follows.

|-						// Root directory/ node_modules npm i can be downloaded
|- src 				// Business logic code
|   |-app.js 			// Script file entry, file interaction logic started
|   |-fundMarket.js 	// Fund related interface logic
|   |-sendMail.js 		// Mail sending logic
|   |-util.js			// Some tools and methods
|-config.js			// configuration file
|-package-lock.json	// The local file is generated by installing the npm package. It is not important
|-package.json 		// npm package management file, you can see the configuration and dependent versions of some projects

(1) SMTP mail service configuration

   first of all, let's meet the requirements of sending mail (I use qq mailbox here, so I need to start the SMTP service of qq mailbox first)

  1. First, select an email that can open smtp service. Here, open the qq email web page, click "Settings" - "account" to enter the following page.

  1. After entering the "account" page, turn down and see the content in the figure below, then select one of the SMTP services, choose one from two, and click "open".

  1. To open the mailbox, you need to keep the mobile phone number secret and send a text message to the number below. This should be for personal identity authentication, which can only be set by the following methods.

  1. After sending the text message, click "I have sent", and then the pop-up box below will pop up. The authorization code here should be saved, and it will be used by the mail service later.

  1. After completing the above steps, even if the SMTP service of the mailbox is enabled, other mailbox opening services should be similar, which will not be introduced here.

(2) Mail sending code implementation

  here I extract some fixed parameter configurations/ config.js folder for easy modification and use. The following is the configuration file.

/** Related parameter configuration of leek reminder */
module.exports = {
  //Mailbox related parameters
  mailboxParameters: {
    host: `smtp.qq.com`, //If the service address is a qq mailbox, it does not need to be changed here
    port: 465, //The smtp port does not need to be changed by default
    secureConnection: true, // Use SSL mode (secure mode to prevent information from being stolen)
    auth: {
      user: `***Write your own here***@foxmail.com`, // user name
      pass: `***Open above SMTP Authorization code obtained by the service***` // SMTP authorization code qq authorization code 
    }
  }
}
// The user and pass under auth above can be filled in with your email and authorization code

   after writing the parameters, the code implementation of the mail sending part is realized. In/ Create sendmail under src JS file, in which relevant business logic is written. The following is the part of code implementation.

const nodemailer = require('nodemailer')
const smtpTransport = require('nodemailer-smtp-transport')
//Get parameters from configuration file
const { mailboxParameters } = require('../config');

//Create smtp service connection object
const transport = nodemailer.createTransport(smtpTransport(mailboxParameters))

/**
 * Send mail function
 * @param {JSON} body Sent message structure 
 */
const sendMail = async (body) => {
  try {
    const res = await transport.sendMail({
      from: mailboxParameters.auth.user, //Sender email
      ...body
    });
    console.log(`\n------ Sent successfully ------\n`, res, `\n------ time ${new Date().toLocaleString()} ------\n`);
  } catch (e) {
    console.log(`\n------ fail in send------\n`, e, `\n------ time ${new Date().toLocaleString()} ------\n`);
  }
}

module.exports = sendMail;

/* 
// Example
sendMail({
  to: '*******@qq.com', // to: "***@qq.com,***2@qq.com", //Target mailbox. Multiple mailboxes are separated by commas
  subject: 'Green leek inform ', / / Title
  text: 'An email from zero-d ', / / when there is no html, text will be used to send the content
  html: `
    <p>Hello</ p>
    <p>${'China stock index plummeted, bottom reading '}</p>
    <p>Drop over: < strong style = "color: #ff4e2a;" >$ {2.0}</strong> </p>
    <p>***You want to copy its bottom, it wants to copy your home! There are risks in the fund. Be careful when buying the base***</ p>
    ` // html content
})
 */

    after writing the code, if you want to test in the code, you can annotate the above example, fill in the receiving mailbox to, and then enter node sendmail JS will run to send the sample mail to the target mailbox. After the test is successful, the mail sending function is completed. Congratulations (◍◍◍◍ノ゙).

(3) Fund interface data crawling

  the method of interface acquisition has been introduced before Daily fund data interface description article Or get it yourself. Of course, there are ready-made ones. You must use ready-made ones φ (∇ ) ; Like the email, some parameters of the fund are also written in config JS configuration file (ps: the relevant parameters of mailbox and fund are written together and explained separately here). The fund parameter configuration is as follows:

/** Related parameter configuration of leek reminder */
module.exports = {
  //Daily fund related interface parameters
  fundParameters: {
    /**
     * Interface to get all fund lists
     * Return value:
     * json array form of fund code, fund name single spelling, fund name Chinese, fund type and fund name full spelling.
     */
    allFundUrl: `http://fund.eastmoney.com/js/fundcode_search.js`,
    /**
     * Access to real-time information interface of single fund
     * Only the unchanged part of the address is saved here
     * Fund interface: http://fundgz.1234567.com.cn/js/519983.js?rt=1463558676006
     * Note: 519983 in the above website is the fund code, and rt=1463558676006 is the timestamp to avoid caching
     * The format of the return value is:
     * jsonpgz(JSON Format data);
     * fundcode  =>  "519983"             //Fund code
     * name      =>  "Changxin quantitative pioneer hybrid A "/ / fund name
     * jzrq      =>  "2018-09-21"         //Net worth date
     * dwjz      =>  "1.2440"             //Net value of the day
     * gsz       =>  "1.2388"             //Estimated net worth
     * gszzl     =>  "-0.42"              //Estimated percentage of rise and fall is -0.42%
     * gztime    =>  "2018-09-25 15:00"   //Valuation time
     */
    realTimeInfoUrl: `http://fundgz.1234567.com.cn/js/`,
    /**
     * Fund details address
     * http://fund.eastmoney.com/pingzhongdata/519983.js?v=20160518155842
     * Note: the red part 519983 in the above website is the fund code; v=20160518155842 is the timestamp to avoid caching.
     * The returned value has Chinese comments
     */
    detailUrl: `http://fund.eastmoney.com/pingzhongdata/`,
    /**
     * Name code list interface of all fund companies
     * http://fund.eastmoney.com/js/jjjz_gs.js?dt=1463791574015
     * Return value: fund company code, fund company name, Chinese
     * I can't use it here for the time being
     * 
     * The above interfaces refer to Tiantian fund network http://www.27ba.com/post/683.html
     */
  }
}

   three URL interfaces related to the fund are written above, but this time only uses the interface to obtain the real-time information of a single fund, and the remaining two are temporarily useless. If you want to do the B/S mode, you can flexibly select the fund and adjust parameters through the web page, and you can do it later! At present, only the node script mode is implemented. Next, let's look at the code implementation of fund information acquisition in/ Create FundMarket under src JS file, in which the fund interface data acquisition method is written. The following is the part of code implementation.

const axios = require("axios")
//Fund parameters
const { fundParameters: { allFundUrl, realTimeInfoUrl, detailUrl } } = require("../config")

/**
 * Obtain brief information on all funds
 * @returns {JSON} Fund list
 */
const getFundList = async () => {
  try {
    const res = await axios({ url: allFundUrl, method: `get` });
    //The returned data is the string content of the two-dimensional array, and the configuration file has the corresponding var r = = ["00000 1", "hxczhh", "Huaxia growth hybrid", "hybrid partial stock", "huaxiachengzhanghunhe"], ["00000 2", "hxczhh"
    eval(res.data);
    return r;
  } catch (e) {
    console.error(`\n------ Error getting fund list information ------\n`, e, `\n------  time ${new Date().toLocaleString()}  ------\n`);
    return null;
  }
}

/**
 * Get data for a single fund
 * Fund interface: http://fundgz.1234567.com.cn/js/519983.js?rt=1463558676006
 * Note: 519983 in the above website is the fund code, and rt=1463558676006 is the timestamp to avoid caching.
 * The format of the return value is:
 * jsonpgz(JSON Format data);
 * @param {String} code Fund code 
 * @returns {JSON} Fund information object
 */
const getFundData = async (code) => {
  /** Parsing json for return parameters */
  const jsonpgz = (jsonStr) => {
    return jsonStr;
  }

  try {
    const url = `${realTimeInfoUrl + code}.js?rt=${new Date().getTime()}`;
    const res = await axios({ url, method: `get` });
    let data = eval(res.data);
    return data;
  } catch (e) {
    console.error(`\n------ Error getting single fund information ------\n`, e, `\n------  time ${new Date().toLocaleString()}  ------\n`);
    return null;
  }
}

/**
 * Interface for obtaining fund details
 * @param {String} code Fund code 
 * @returns {String} Return a section of fund information code with Chinese annotation
 */
const getFundDetail = async (code) => {
  try {
    const res = await axios({ url: `${detailUrl + code}.js?v=${new Date().getTime()}`, method: `get` });
    return res.data;
  } catch (e) {
    console.error(`\n------ Error getting detailed fund information ------\n`, e, `\n------  time ${new Date().toLocaleString()}  ------\n`);
    return null;
  }
}

module.exports = {
  getFundList,
  getFundData,
  getFundDetail
}
//Throw the above three methods for external calls

(4) Subscription fund valuation

    it's time to "freeze the hearts of the chickens". Write the main business code and deal with the needs again. If you want to pay attention to the rise and fall of the valuation of some funds, you will send an email notice when the rise and fall reaches a certain threshold. Since the fund is closed at 3 o'clock every day, the best operation time is generally between 2:30 and 3 o'clock, because there is generally no much difference between the valuation and the final result at this time, Therefore, the qualified fund valuation information will be sent regularly at 2:30/ Create app under src JS file, write the main business logic, and the following is the code implementation.

const schedule = require("node-schedule");
const sendMail = require("./sendMail"); //Mail sending
const { getDay } = require("./utils"); //The date of the day will not be displayed here. The source code of the whole project will be uploaded at that time
const { getFundData } = require("./fundMarket"); //Fund interface information

// early warn defines the threshold of the rise and fall range. The first is the lower number of notifications, and the second is the higher number of notifications
const EW = [-1, 1];
//Code that defines the fund list to subscribe to
const codeList = ['161725', '013278', '163406', '166002', '163402', '001410', '260108', '004241', '002697', '003096', '005242'];
// The mailbox number of the subscription is the target mailbox. Multiple mailboxes are separated by commas
const users = `*****@qq.com`;

/**
 * Get the fund market subscribed on that day
 */
const fundEarlyWarning = async () => {
  try {
    //Get fund information in the list
    const resList = await Promise.all(codeList.map(code => getFundData(code)));
    if (!resList.length) {
      console.log(`\n------ ${new Date().toLocaleString()}-No fund information was obtained ------\n`);
      return;
    }
    //Consider whether to open the market. Here, the getDay function obtains the time in the format of XXXX-XX-XX. The code is not shown in the article because it is relatively simple. You can view the source code
    if (resList[0].gztime.split(" ")[0] !== getDay()) {
      console.log(`\n------ ${new Date().toLocaleString()}-The market is not open today ------\n`);
      return;
    }
    // Filter out qualified funds
    const fundList = resList.filter(fd => (fd.gszzl < EW[0] || fd.gszzl > EW[1]))
    if (!fundList.length) {
      //Send mail
      sendMail({
        to: users, // to: "***@qq.com,***2@qq.com ", / / target mailbox. Multiple mailboxes are separated by commas
        subject: '[Leek post zero notice] today's market', // title
        text: `Today, the range of rise and fall is ${EW}Inside, it is recommended to be a safe leek!`, //When there is no html, text is used to send the content
      })
      console.log(`\n------ ${new Date().toLocaleString()}-There are no funds eligible for notification ------\n`);
      return;
    }
    //Email send
    emailNotify(fundList);
  } catch (e) {
    console.error(`\n------ Fund notification error ------\n`, e, `\n------  time ${new Date().toLocaleString()}  ------\n`);
  }
}

/**
 * Send e-mail notification according to the rise and fall of subscription funds
 * @param {Array} data 
 */
const emailNotify = (data) => {
  try {
    //Write the content first
    let notifyStr = "";
    data.forEach(fd => {
      let flag = fd.gszzl < 0; //Judge whether it is down or up
      notifyStr += `
        <tr>
          <td style="border: 1px solid #6495ed;">${fd.name + '-' + fd.fundcode}</td>
          <td style="border: 1px solid #6495ed;"><strong style="color: ${flag ? 'green' : 'red'};">${fd.gszzl}%</strong></td>
          <td style="border: 1px solid #6495ed; color: ${flag ? 'green' : 'red'}; "> ${flag? 'selling Soha!': 'it's safe to drop the bag'}</td>
          <td style="border: 1px solid #6495ed;">${fd.gztime}</td>
        </tr>
      `
    });
    //Overall html content
    const html = `
    <table cellspacing="0" cellpadding="5px" style="font-family:'Microsoft YaHei ',Helvetica,Arial,sans-serif;color: #2C3E50;font-size:10px;">
      <tbody>
        <tr>
          <th style="border: 1px solid #6495ed; "> fund name & code < / th >
          <th style="border: 1px solid #6495ed; "> estimated percentage of rise and fall < / th >
          <th style="border: 1px solid #6495ed; "> recommended actions < / th >
          <th style="border: 1px solid #6495ed; "> valuation time < / th >
        </tr>
        ${notifyStr}
      </tbody>
    </table>
    `;
    //Send mail
    sendMail({
      to: users, // to: "***@qq.com,***2@qq.com ", / / target mailbox. Multiple mailboxes are separated by commas
      subject: '[Leek post zero notice] today's market', // title
      text: 'No, html,So it happened txt', //When there is no html, text is used to send the content
      html
    })
  } catch (e) {
    console.error(`\n------ Send mail error ------\n`, e, `\n------  time ${new Date().toLocaleString()}  ------\n`);
  }
}

//Timed trigger task
const signTask = () => {
  //Inform today's market at 2:30 every day
  schedule.scheduleJob("0 30 14 * * *", () => {
    fundEarlyWarning();
  })
}

//Start scheduled task
console.clear()
console.log(`\n------ Start script execution-Time: ${new Date().toLocaleString()}  ------\n`);
signTask();

   although the requirements to be realized are relatively simple, it still takes some effort to write the code, especially the table. Writing html code in js is really a bit of mentality (. -), But it took me a little time at most. I put the code data of subscribed funds in an array codeList. If I want to use it, I can put the fund code I pay attention to in it, and then set a rise and fall threshold EW. If the valuation exceeds the threshold, I will filter out the qualified funds in the fund list and send them to users in the subscription mailbox, The time of sending e-mail can be set according to my own needs. I generally like to see the valuation changes of the fund at 2:30 p.m. Here, the increase or decrease of subscription funds is realized by controlling codeList, and the threshold EW is used to control the number of funds sent. Users is the mailbox to be received. In fact, these parameters can be checked in one interface to reduce the trouble caused by code modification, but the workload is too large, so you can implement it when you have time! Of course, interested partners can try to achieve it! ヾ(o・ ω・) The following is the fund information subscribed today. They all fell! (t ▽ T) "falling endlessly" belongs to yes.

4, Conclusion

  last issue node automatic check-in At the time of writing the article, I already thought about writing an article about node sending e-mail, but after writing the e-mail sending code, I found that it was too simple. Just recently, the fund I bought fell sharply. I just remembered that I had such an idea before, so I planned to realize the idea of fund valuation subscription in combination with e-mail sending. Unexpectedly, today's fund is green again. It's terrible! tragic beyond compare in this human world! (t ▽ T) in short, I'm very happy that the code has been implemented. I got a new posture of "Ga leek". I lay flat and let it go with the wind!

  there are risks in the stock market, so be cautious in investing! The content of this article does not constitute any investment suggestions, but only a code implementation technology sharing article for obtaining fund information. Welcome those who love technology and are willing to be "leeks" to discuss. If there are any mistakes in this article, please correct them ω・) Thank you for your patient reading. If you can help me, please don't move your little hand and give me a compliment. Thank you very much! φ (> ω<*)

5, Source code & Reference

  1. Reference to fund information: http://www.27ba.com/post/683.html
  2. The source code is on gitee. Welcome to clone, address: https://gitee.com/zero-dg/fund_subscription.git

Keywords: node.js Front-end IDE

Added by Altairzq on Wed, 12 Jan 2022 03:14:12 +0200