# 4-2. Moving Volume Weighted Average Price (MVWAP) In this "MVWAP" data process demonstration, in addition to logic writing, we will be focusing on the ++**design thinking of the entire process**++ and the ++**use of agents**++. ## Before LOC Setup - At the beginning of the entire process, we need to go through the analysis process(BA/SA) to clarify the needs to help developers build up data processes. - After we specify our requirements in BA/SA process, we have designed where/what/how users can get MVWAP index and mapped these requirements back to design: - What **Trigger** point does the user use to execute a data process? - Which **Data Source** should the user read/write? - Finally, what kind of **Output** does user want? *Here since we do not introduced the event concept, there is no setup in Reference.* ![](https://i.imgur.com/PFZQDIY.jpg) - We know that users want to be able to obtain the specific stock MVWAP index. Based on this requirement, we use the expected API as a starting point to design the whole data process. ![](https://i.imgur.com/MVEX9OK.jpg) - After designing the data process, we can start to setup it with LOC. --- ## Step 1. Initiate New Data Process Template File At the beginning, let us start the whole journey by ``` loc login ``` And ``` loc new [template name] ``` --- ## Step 2. Edit API Route yaml file ![](https://i.imgur.com/pbfmAYc.jpg) - After designing and planning, we can know the API schema that we expect to build and users expect to access. That we can set it in the `api-route-config.yaml` first. - API Route: You need to (1) change to POST method to bring payload to the generic logic to parse value; (2) rename the API route name that you favour, such as **MVWAP_sample**; (3) create your own path, such as **/sample/getMVWAP**; and leave the rest unchanged. ```yaml= method: Post mode: Sync encapsulation: false name: MVWAP_sample path: /sample/getMVWAP dataProcessPids: - pid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx revision: latest ``` --- ## Step 3. Create Generic Logic - To build a "MVWAP" data process, we need to: (1) parse the payload that users key in; (2) get necessary data that we need through DB agent; (3) calculate the index (MVWAP); and (4) print out the result of calculations. - **3.1 Parse API Payload** ```javascript= export async function run(ctx) { // checking input from api if ("event" in ctx.payload || "messageQueue" in ctx.payload) { throw new Error("this logic accept http payload only"); } // a function that transforms byte array to string function UTF8ArrToStr(aBytes) { let utf8decoder = new TextDecoder(); return utf8decoder.decode(new Uint8Array(aBytes)); } const getHttpBodyJson = JSON.parse(UTF8ArrToStr(ctx.payload.http.body)); // parse payload body const data_payload = getHttpBodyJson; // checking the payload is as defined const days = parseInt(data_payload.days ?? "0"); const stock_code = data_payload.stock_code ?? ""; if (stock_code == ""){ throw "please enter the correct stock code." } if (days !== 20 && days !== 50 && days !== 100) { throw "days should be 20 | 50 | 100"; } ``` > Check whether the input of days is 20, 50 or 100 days. > Check whether users search with a correct stock_code. - **3.2 Connect DB and Query Data** ```javascript=31 // mysql authorized access const database = process.env.db1_database; const table = process.env.db1_table4; let connection = new Saffron.Database.MySqlParameters({ host: process.env.db1_host, port: parseInt(process.env.db1_port ?? "3306"), database, username: process.env.db1_username, password: process.env.db1_password, }); let db = await ctx.agents.database?.connect({ databaseDriver: Saffron.Database.Driver.MySql, connection, }); let sql = `SELECT stock_code, close, volume, date \ FROM ${table} \ WHERE stock_code = '${stock_code}' \ ORDER BY date DESC \ LIMIT ${days};` let resp = await db?.query(sql, []); ``` > `process.env` means to get the information in `profile.yaml` - **3.3 Calculate MVWAP** ```javascript=56 // calculate MVWAP let numerator_vwap = 0; let denominator_vwap = 0; resp?.rows.forEach((row) => { numerator_vwap += Number(row["close"] * row["volume"]) denominator_vwap += Number(row["volume"]); }) let vwap = Number(numerator_vwap) / Number(denominator_vwap); let mvwap = Number(vwap) / Number(days); ``` - **3.4 API Response** ```javascript=66 // push result in array let data = []; data.push({stock_code: stock_code, MVWAP: mvwap, VWAP: vwap, Numerator: numerator_vwap, Denominator: denominator_vwap}); await ctx.agents.sessionStorage.putJson("result", data) } ////////////////////////////////////////////////// export async function handleError(ctx, error) { ctx.agents.logging.error(error.message); } ``` --- ## Step 4. Create Aggregator Logic - Finalise and aggregate the result that we need to show up in the API response. ```javascript= export async function run(ctx) { let result = { Status: 200, Message: 'Calling API success.', API_calling_details: await ctx.agents.sessionStorage.get("result"), }; ctx.agents.result.finalize(result); } export async function handleError(ctx, error) { ctx.agents.logging.error(error.message); let result = { status: 500, errorMessage: `An error occurs when calling API. Error: ${error.message}`, }; ctx.agents.result.finalize(result); } ``` :::info ADDITIONAL Edit Configuration - Configuration: You can also edit your `config.yaml` for readable (1) rename the configuration name that you favour, such as **MVWAP_sample**; (2) rename the logic names that you favour, such as **MVWAP_sample_code.js**; ```yaml= version: 0.1.0 name: MVWAP_sample description: description timeoutSeconds: 180 aggregatorLogic: name: aggregator file: aggregator-logic.js genericLogics: - name: MVWAP_sample file: MVWAP_sample_code.js ``` ::: --- ## Step 5. Deploy Data Process and API Route - Once the setting above is completed, we can deploy "MVWAP" ++data process++ and ++API route++ at the same time by using command: `loc deploy [template name] -ar`. Here we use `loc deploy MVWAP_sample_code -ar`. ![](https://i.imgur.com/EAgDMGh.jpg) --- ## Step 6. Trigger API Route with Payload Here we use ++Postman++ to demonstrate. - Select ```POST``` and use the endpoint path we set in ```api-route-config.yaml``` with domain URL. Afterwards, use the JSON payload as below to get the data that we need: ++**payload**++ ```json= { "days":20, "stock_code":"1301" } ``` - Click `Send` , here is the response that you can expect, in which to get the `MVWAP` index of `stock_code:1301`, with lots of additional information. ![](https://hackmd.io/_uploads/rksPyunko.png) --- ###### tags: `Workshop`