├── .expo-shared └── assets.json ├── .gitignore ├── .watchmanconfig ├── App.js ├── Index.js ├── README.md ├── __tests__ └── App-test.js ├── app.json ├── assets ├── fonts │ └── SpaceMono-Regular.ttf └── images │ ├── Crypto.jpg │ ├── favicon.png │ ├── icon.png │ ├── iconCapital.png │ ├── iron-man.png │ ├── marketOverall.jpg │ ├── robot-dev.png │ ├── robot-prod.png │ ├── sector.jpg │ ├── splash.png │ └── stockScreen.jpg ├── babel.config.js ├── components ├── Crypto │ └── TreeMap.js ├── Home │ └── StockChart.js ├── Sector │ └── SectorChart.js ├── Stock │ ├── Chart.js │ ├── InfoSlideOne.js │ ├── InfoSlideThree.js │ ├── InfoSlideTwo.js │ └── Input.js ├── StyledText.js ├── TabBarIcon.js ├── __tests__ │ ├── StyledText-test.js │ └── __snapshots__ │ │ └── StyledText-test.js.snap ├── sector │ └── SectorChart.js └── stock │ ├── Chart.js │ └── Input.js ├── constants ├── Colors.js └── Layout.js ├── hooks └── useCachedResources.js ├── navigation ├── BottomTabNavigator.js └── LinkingConfiguration.js ├── package-lock.json ├── package.json └── screens ├── MarketOverview.js ├── SectorScreen.js ├── StockScreen.js └── utils.js /.expo-shared/assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "e997a5256149a4b76e6bfd6cbf519c5e5a0f1d278a3d8fa1253022b03c90473b": true, 3 | "af683c96e0ffd2cf81287651c9433fa44debc1220ca7cb431fe482747f34a505": true, 4 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, 5 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p8 6 | *.p12 7 | *.key 8 | *.mobileprovision 9 | *.orig.* 10 | web-build/ 11 | 12 | # macOS 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import { NavigationContainer } from '@react-navigation/native'; 2 | import { createStackNavigator } from '@react-navigation/stack'; 3 | import * as React from 'react'; 4 | import { Platform, StatusBar, StyleSheet, View } from 'react-native'; 5 | 6 | import useCachedResources from './hooks/useCachedResources'; 7 | import BottomTabNavigator from './navigation/BottomTabNavigator'; 8 | import LinkingConfiguration from './navigation/LinkingConfiguration'; 9 | 10 | const Stack = createStackNavigator(); 11 | 12 | export default function App(props) { 13 | const isLoadingComplete = useCachedResources(); 14 | 15 | if (!isLoadingComplete) { 16 | return null; 17 | } else { 18 | return ( 19 | 20 | {Platform.OS === 'ios' && } 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | } 29 | } 30 | 31 | const styles = StyleSheet.create({ 32 | container: { 33 | flex: 1, 34 | backgroundColor: '#fff', 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /Index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import store from './stores/store'; 4 | import App from './App'; 5 | 6 | export default class Index extends Component { 7 | render() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Financial InfoX 2 | 3 | `Tech Used:` React-Native, native-echarts, expo, antd-mobile,react-navigation 4 | 5 | ## Description: 6 | 7 | A mobile app built in 3 days to demonstrate stock market information by using a variety of charts, especially candlestick charts. In addition, used a tree­map (whcih now is not working, need API resource) to illustrate asset value for Cryptocurrency market. 8 | 9 | ## Updated: 10 | Updated In May 2020 to adapt to all new packages and make the project alive again! 11 | 12 | ## Screen Shots demonstration 13 | 14 | 15 | 16 | 17 | 18 | 19 | #### Question? 20 | 21 | Now, if you have question, please let me know. 22 | -------------------------------------------------------------------------------- /__tests__/App-test.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import App from '../App'; 4 | import renderer from 'react-test-renderer'; 5 | import NavigationTestUtils from 'react-navigation/NavigationTestUtils'; 6 | 7 | describe('App snapshot', () => { 8 | jest.useFakeTimers(); 9 | beforeEach(() => { 10 | NavigationTestUtils.resetInternalState(); 11 | }); 12 | 13 | it('renders the loading screen', async () => { 14 | const tree = renderer.create().toJSON(); 15 | expect(tree).toMatchSnapshot(); 16 | }); 17 | 18 | it('renders the root without loading screen', async () => { 19 | const tree = renderer.create().toJSON(); 20 | expect(tree).toMatchSnapshot(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "StockProject", 4 | "slug": "StockProject", 5 | "platforms": [ 6 | "ios", 7 | "android", 8 | "web" 9 | ], 10 | "version": "1.0.0", 11 | "orientation": "portrait", 12 | "icon": "./assets/images/icon.png", 13 | "scheme": "myapp", 14 | "splash": { 15 | "image": "./assets/images/splash.png", 16 | "resizeMode": "contain", 17 | "backgroundColor": "#ffffff" 18 | }, 19 | "updates": { 20 | "fallbackToCacheTimeout": 0 21 | }, 22 | "assetBundlePatterns": [ 23 | "**/*" 24 | ], 25 | "ios": { 26 | "supportsTablet": true 27 | }, 28 | "web": { 29 | "favicon": "./assets/images/favicon.png" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /assets/fonts/SpaceMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/fonts/SpaceMono-Regular.ttf -------------------------------------------------------------------------------- /assets/images/Crypto.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/Crypto.jpg -------------------------------------------------------------------------------- /assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/favicon.png -------------------------------------------------------------------------------- /assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/icon.png -------------------------------------------------------------------------------- /assets/images/iconCapital.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/iconCapital.png -------------------------------------------------------------------------------- /assets/images/iron-man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/iron-man.png -------------------------------------------------------------------------------- /assets/images/marketOverall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/marketOverall.jpg -------------------------------------------------------------------------------- /assets/images/robot-dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/robot-dev.png -------------------------------------------------------------------------------- /assets/images/robot-prod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/robot-prod.png -------------------------------------------------------------------------------- /assets/images/sector.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/sector.jpg -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/splash.png -------------------------------------------------------------------------------- /assets/images/stockScreen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/0ab5a4a1b2fd770851df2f1d4f9dd38413eccde6/assets/images/stockScreen.jpg -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /components/Crypto/TreeMap.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { StyleSheet, View, Platform } from "react-native"; 3 | import Echarts from "native-echarts"; 4 | import { useEffect, useState } from "react"; 5 | import axios from "axios"; 6 | const CryptoTreeMap = () => { 7 | const [cryptoData, setCryptoData] = useState(null); 8 | const fetchSector = async () => { 9 | try { 10 | const sectorRes = await axios.get( 11 | `https://www.alphavantage.co/query?function=SECTOR&apikey=demo` 12 | ); 13 | setSectorData(sectorRes.data[`Rank B: 1 Day Performance`]); 14 | } catch (error) { 15 | console.log(error); 16 | } 17 | }; 18 | 19 | useEffect(() => { 20 | fetchSector(); 21 | }, []); 22 | const name = "Market Change by (%)"; 23 | const sectors = Object.keys(sectorData); 24 | const performance = Object.values(sectorData).map((e) => 25 | parseFloat(e).toFixed(2) 26 | ); 27 | 28 | const option = { 29 | tooltip: { 30 | trigger: "axis", 31 | axisPointer: { 32 | type: "shadow", 33 | }, 34 | }, 35 | legend: { 36 | data: [name], 37 | textStyle: { 38 | color: "white", 39 | }, 40 | }, 41 | grid: { 42 | left: "1%", 43 | right: "4%", 44 | bottom: "3%", 45 | containLabel: true, 46 | }, 47 | xAxis: [ 48 | { 49 | type: "value", 50 | axisLine: { 51 | lineStyle: { color: "white" }, 52 | }, 53 | axisTick: { show: false }, 54 | }, 55 | ], 56 | yAxis: [ 57 | { 58 | type: "category", 59 | axisTick: { show: false }, 60 | axisLine: { 61 | lineStyle: { color: "white" }, 62 | }, 63 | splitLine: { show: false, color: "black" }, 64 | data: sectors, 65 | }, 66 | ], 67 | series: [ 68 | { 69 | name: name, 70 | type: "bar", 71 | label: { 72 | normal: { 73 | show: true, 74 | position: "inside", 75 | }, 76 | }, 77 | data: performance, 78 | }, 79 | ], 80 | }; 81 | return ( 82 | 83 | 84 | 85 | ); 86 | }; 87 | 88 | const styles = StyleSheet.create({ 89 | container: { 90 | flex: 1, 91 | paddingLeft: 10, 92 | paddingRight: 10, 93 | backgroundColor: "black", 94 | }, 95 | nameBlock: { 96 | flex: 1, 97 | paddingTop: 4, 98 | justifyContent: "center", 99 | alignItems: "center", 100 | }, 101 | nameText: { 102 | fontWeight: "bold", 103 | fontSize: 12, 104 | color: "white", 105 | }, 106 | details: { 107 | flex: 5, 108 | flexDirection: "column", 109 | borderTopWidth: StyleSheet.hairlineWidth, 110 | borderBottomWidth: StyleSheet.hairlineWidth, 111 | borderColor: "white", 112 | }, 113 | detailsRow: { 114 | flex: 1, 115 | flexDirection: "row", 116 | alignItems: "center", 117 | justifyContent: "space-between", 118 | marginTop: 10, 119 | }, 120 | detailsRowColumn: { 121 | flex: 1, 122 | flexDirection: "row", 123 | alignItems: "center", 124 | justifyContent: "space-between", 125 | paddingLeft: 5, 126 | paddingRight: 5, 127 | }, 128 | separator: { 129 | height: StyleSheet.hairlineWidth, 130 | backgroundColor: "white", 131 | marginTop: 20, 132 | }, 133 | separatorThin: { 134 | height: StyleSheet.hairlineWidth, 135 | backgroundColor: "#A6A6A6", 136 | }, 137 | propertyText: { 138 | fontSize: 12, 139 | color: "#A6A6A6", 140 | textAlign: "left", 141 | }, 142 | valueText: { 143 | fontSize: 15, 144 | color: "white", 145 | textAlign: "right", 146 | }, 147 | title: { 148 | paddingTop: 5, 149 | color: "white", 150 | fontSize: 15, 151 | fontWeight: "bold", 152 | textAlign: "center", 153 | justifyContent: "center", 154 | alignItems: "center", 155 | }, 156 | }); 157 | 158 | export default SectorChart; 159 | -------------------------------------------------------------------------------- /components/Home/StockChart.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { StyleSheet, View, Platform } from "react-native"; 3 | import Echarts from "native-echarts"; 4 | 5 | const StockChart = ({ data, name }) => { 6 | let stockData = data.slice(-30); 7 | 8 | let dates = []; 9 | let values = []; 10 | 11 | if (data) { 12 | stockData.map((data) => dates.push(data["date"])); 13 | stockData.map((item) => 14 | values.push([item["open"], item["close"], item["low"], item["high"]]) 15 | ); 16 | } 17 | 18 | const option = { 19 | backgroundColor: "black", 20 | title: { 21 | show: true, 22 | text: name, 23 | textStyle: { 24 | fontSize: 15, 25 | align: "center", 26 | lineHeight: 40, 27 | left: "40%", 28 | }, 29 | }, 30 | tooltip: { 31 | trigger: "none", 32 | axisPointer: { 33 | animation: false, 34 | type: "cross", 35 | lineStyle: { 36 | color: "#376df4", 37 | width: 2, 38 | opacity: 1, 39 | }, 40 | }, 41 | }, 42 | 43 | toolbox: { 44 | orient: "vertical", 45 | show: true, 46 | showTitle: true, 47 | }, 48 | xAxis: [ 49 | { 50 | type: "category", 51 | data: dates, 52 | axisLine: { lineStyle: { color: "white" } }, 53 | scale: true, 54 | }, 55 | ], 56 | yAxis: [ 57 | { 58 | scale: true, 59 | axisLine: { 60 | lineStyle: { color: "white" }, 61 | }, 62 | splitLine: { show: false }, 63 | }, 64 | ], 65 | grid: [ 66 | { 67 | top: 40, 68 | bottom: 40, 69 | left: 50, 70 | }, 71 | ], 72 | color: ["rgb(249,159,94)", "rgb(67,205,126)"], 73 | animation: true, 74 | series: [ 75 | { 76 | type: "candlestick", 77 | name: "Daily", 78 | data: values, 79 | itemStyle: { 80 | normal: { 81 | color: "#FD1050", 82 | color0: "#0CF49B", 83 | borderColor: "#FD1050", 84 | borderColor0: "#0CF49B", 85 | }, 86 | }, 87 | }, 88 | ], 89 | }; 90 | return ( 91 | 92 | 98 | 99 | ); 100 | }; 101 | 102 | const styles = StyleSheet.create({ 103 | container: { 104 | flex: 1, 105 | }, 106 | 107 | titleView: { 108 | height: Platform.OS == "ios" ? 20 : 44, 109 | paddingTop: Platform.OS == "ios" ? 0 : 0, 110 | backgroundColor: "black", 111 | justifyContent: "center", 112 | alignItems: "center", 113 | }, 114 | title: { 115 | color: "white", 116 | fontSize: 15, 117 | fontWeight: "bold", 118 | textAlign: "center", 119 | }, 120 | }); 121 | 122 | export default StockChart; 123 | -------------------------------------------------------------------------------- /components/Sector/SectorChart.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { StyleSheet, View, Platform } from "react-native"; 3 | import Echarts from "native-echarts"; 4 | import { useEffect, useState } from "react"; 5 | import axios from "axios"; 6 | const SectorChart = () => { 7 | const [sectorData, setSectorData] = useState([]); 8 | const fetchSector = async () => { 9 | try { 10 | const sectorRes = await axios.get( 11 | `https://www.alphavantage.co/query?function=SECTOR&apikey=demo` 12 | ); 13 | setSectorData(sectorRes.data[`Rank B: 1 Day Performance`]); 14 | } catch (error) { 15 | console.log(error); 16 | } 17 | }; 18 | 19 | useEffect(() => { 20 | fetchSector(); 21 | }, []); 22 | const name = "Market Change by (%)"; 23 | const sectors = Object.keys(sectorData); 24 | const performance = Object.values(sectorData).map((e) => 25 | parseFloat(e).toFixed(2) 26 | ); 27 | 28 | const option = { 29 | tooltip: { 30 | trigger: "axis", 31 | axisPointer: { 32 | type: "shadow", 33 | }, 34 | }, 35 | legend: { 36 | data: [name], 37 | textStyle: { 38 | color: "white", 39 | }, 40 | }, 41 | grid: { 42 | left: "1%", 43 | right: "4%", 44 | bottom: "3%", 45 | containLabel: true, 46 | }, 47 | xAxis: [ 48 | { 49 | type: "value", 50 | axisLine: { 51 | lineStyle: { color: "white" }, 52 | }, 53 | axisTick: { show: false }, 54 | }, 55 | ], 56 | yAxis: [ 57 | { 58 | type: "category", 59 | axisTick: { show: false }, 60 | axisLine: { 61 | lineStyle: { color: "white" }, 62 | }, 63 | splitLine: { show: false, color: "black" }, 64 | data: sectors, 65 | }, 66 | ], 67 | series: [ 68 | { 69 | name: name, 70 | type: "bar", 71 | label: { 72 | normal: { 73 | show: true, 74 | position: "inside", 75 | }, 76 | }, 77 | data: performance, 78 | }, 79 | ], 80 | }; 81 | return ( 82 | 83 | 84 | 85 | ); 86 | }; 87 | 88 | const styles = StyleSheet.create({ 89 | container: { 90 | flex: 1, 91 | paddingLeft: 10, 92 | paddingRight: 10, 93 | backgroundColor: "black", 94 | }, 95 | nameBlock: { 96 | flex: 1, 97 | paddingTop: 4, 98 | justifyContent: "center", 99 | alignItems: "center", 100 | }, 101 | nameText: { 102 | fontWeight: "bold", 103 | fontSize: 12, 104 | color: "white", 105 | }, 106 | details: { 107 | flex: 5, 108 | flexDirection: "column", 109 | borderTopWidth: StyleSheet.hairlineWidth, 110 | borderBottomWidth: StyleSheet.hairlineWidth, 111 | borderColor: "white", 112 | }, 113 | detailsRow: { 114 | flex: 1, 115 | flexDirection: "row", 116 | alignItems: "center", 117 | justifyContent: "space-between", 118 | marginTop: 10, 119 | }, 120 | detailsRowColumn: { 121 | flex: 1, 122 | flexDirection: "row", 123 | alignItems: "center", 124 | justifyContent: "space-between", 125 | paddingLeft: 5, 126 | paddingRight: 5, 127 | }, 128 | separator: { 129 | height: StyleSheet.hairlineWidth, 130 | backgroundColor: "white", 131 | marginTop: 20, 132 | }, 133 | separatorThin: { 134 | height: StyleSheet.hairlineWidth, 135 | backgroundColor: "#A6A6A6", 136 | }, 137 | propertyText: { 138 | fontSize: 12, 139 | color: "#A6A6A6", 140 | textAlign: "left", 141 | }, 142 | valueText: { 143 | fontSize: 15, 144 | color: "white", 145 | textAlign: "right", 146 | }, 147 | title: { 148 | paddingTop: 5, 149 | color: "white", 150 | fontSize: 15, 151 | fontWeight: "bold", 152 | textAlign: "center", 153 | justifyContent: "center", 154 | alignItems: "center", 155 | }, 156 | }); 157 | 158 | export default SectorChart; 159 | -------------------------------------------------------------------------------- /components/Stock/Chart.js: -------------------------------------------------------------------------------- 1 | import Echarts from "native-echarts"; 2 | import React, { Component } from "react"; 3 | import { StyleSheet, Text, View, Platform, Dimensions } from "react-native"; 4 | 5 | const { width } = Dimensions.get("window"); 6 | 7 | export default function Chart({ selectedStock }) { 8 | const { data, info } = selectedStock; 9 | const calculateMA = (dayCount, data) => { 10 | const result = []; 11 | for (let i = 0, len = data.length; i < len; i++) { 12 | if (i < dayCount) { 13 | result.push("-"); 14 | continue; 15 | } 16 | var sum = 0; 17 | 18 | for (let j = 0; j < dayCount; j++) { 19 | sum += data[i - j][1]; 20 | } 21 | result.push(sum / dayCount); 22 | } 23 | return result; 24 | }; 25 | 26 | let dates = []; 27 | let values = []; 28 | 29 | if (data) { 30 | data.map((stockData) => dates.push(stockData["date"])); 31 | data.map((item) => 32 | values.push([item["open"], item["close"], item["low"], item["high"]]) 33 | ); 34 | } 35 | const option = { 36 | backgroundColor: "black", 37 | tooltip: { 38 | trigger: "none", 39 | axisPointer: { 40 | animation: false, 41 | type: "cross", 42 | lineStyle: { 43 | color: "#376df4", 44 | width: 2, 45 | opacity: 1, 46 | }, 47 | }, 48 | }, 49 | legend: { 50 | data: ["MA5", "MA10", "MA20", "MA30"], 51 | inactiveColor: "#777", 52 | textStyle: { 53 | color: "#fff", 54 | }, 55 | }, 56 | toolbox: { 57 | orient: "vertical", 58 | show: true, 59 | showTitle: true, 60 | }, 61 | xAxis: [ 62 | { 63 | type: "category", 64 | data: dates, 65 | axisLine: { lineStyle: { color: "#F3F3F3" } }, 66 | }, 67 | ], 68 | yAxis: [ 69 | { 70 | scale: true, 71 | axisLine: { 72 | lineStyle: { color: "#F3F3F3" }, 73 | }, 74 | splitLine: { show: false }, 75 | }, 76 | ], 77 | grid: [ 78 | { 79 | left: "10%", 80 | right: "8%", 81 | height: "50%", 82 | }, 83 | { 84 | left: "10%", 85 | right: "8%", 86 | bottom: "10%", 87 | height: "15%", 88 | }, 89 | ], 90 | 91 | dataZoom: [ 92 | { 93 | textStyle: { 94 | color: "#F3F3F3", 95 | }, 96 | handleIcon: 97 | "M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", 98 | handleSize: "80%", 99 | dataBackground: { 100 | areaStyle: { 101 | color: "#8392A5", 102 | }, 103 | lineStyle: { 104 | opacity: 0.8, 105 | color: "#8392A5", 106 | }, 107 | }, 108 | handleStyle: { 109 | color: "#fff", 110 | shadowBlur: 3, 111 | shadowColor: "rgba(0, 0, 0, 0.6)", 112 | shadowOffsetX: 2, 113 | shadowOffsetY: 2, 114 | }, 115 | }, 116 | { 117 | type: "inside", 118 | }, 119 | ], 120 | color: ["rgb(249,159,94)", "rgb(67,205,126)"], 121 | animation: true, 122 | series: [ 123 | { 124 | type: "candlestick", 125 | name: "Daily", 126 | data: values, 127 | itemStyle: { 128 | normal: { 129 | color: "#FD1050", 130 | color0: "#0CF49B", 131 | borderColor: "#FD1050", 132 | borderColor0: "#0CF49B", 133 | }, 134 | }, 135 | }, 136 | { 137 | name: "MA5", 138 | type: "line", 139 | data: calculateMA(5, values), 140 | smooth: true, 141 | showSymbol: false, 142 | lineStyle: { 143 | normal: { 144 | width: 1, 145 | }, 146 | }, 147 | }, 148 | { 149 | name: "MA10", 150 | type: "line", 151 | data: calculateMA(10, values), 152 | smooth: true, 153 | showSymbol: false, 154 | lineStyle: { 155 | normal: { 156 | width: 1, 157 | }, 158 | }, 159 | }, 160 | { 161 | name: "MA20", 162 | type: "line", 163 | data: calculateMA(20, values), 164 | smooth: true, 165 | showSymbol: false, 166 | lineStyle: { 167 | normal: { 168 | width: 1, 169 | }, 170 | }, 171 | }, 172 | { 173 | name: "MA30", 174 | type: "line", 175 | data: calculateMA(30, values), 176 | smooth: true, 177 | showSymbol: false, 178 | lineStyle: { 179 | normal: { 180 | width: 1, 181 | }, 182 | }, 183 | }, 184 | ], 185 | }; 186 | 187 | return ( 188 | 189 | 190 | {info && {info["companyName"]}} 191 | 192 | 193 | 194 | 195 | ); 196 | } 197 | const styles = StyleSheet.create({ 198 | container: { 199 | flex: 1, 200 | }, 201 | 202 | titleView: { 203 | height: Platform.OS == "ios" ? 20 : 44, 204 | paddingTop: Platform.OS == "ios" ? 0 : 0, 205 | backgroundColor: "black", 206 | justifyContent: "center", 207 | alignItems: "center", 208 | }, 209 | title: { 210 | color: "white", 211 | fontSize: 15, 212 | fontWeight: "bold", 213 | textAlign: "center", 214 | }, 215 | }); 216 | -------------------------------------------------------------------------------- /components/Stock/InfoSlideOne.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, View } from "react-native"; 3 | 4 | export default function InfoSlideOne({ info }) { 5 | return ( 6 | 7 | 8 | 9 | 10 | 50 DAYS MA 11 | 12 | {parseFloat(info["day50MovingAvg"]).toFixed(2) || "--"} 13 | 14 | 15 | 16 | 200 DAYS MA 17 | 18 | {parseFloat(info["day200MovingAvg"]).toFixed(2) || "--"} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 5 DAYS CHANGE(%) 27 | 28 | {parseFloat(info["day5ChangePercent"]).toFixed(2) || "--"} 29 | 30 | 31 | 32 | 30 DAYS CHANGE(%) 33 | 34 | {parseFloat(info["day30ChangePercent"]).toFixed(2) || "--"} 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 6 MONTH CHANGE(%) 43 | 44 | {parseFloat(info["month6ChangePercent"]).toFixed(2) || "--"} 45 | 46 | 47 | 48 | 1 YEAR CHANGE(%) 49 | 50 | {parseFloat(info["year1ChangePercent"]).toFixed(2) || "--"} 51 | 52 | 53 | 54 | 55 | 56 | 57 | ); 58 | } 59 | const styles = StyleSheet.create({ 60 | container: { 61 | flex: 1, 62 | paddingLeft: 10, 63 | paddingRight: 10, 64 | backgroundColor: "black", 65 | }, 66 | nameBlock: { 67 | flex: 1, 68 | paddingTop: 4, 69 | justifyContent: "center", 70 | alignItems: "center", 71 | }, 72 | nameText: { 73 | fontWeight: "bold", 74 | fontSize: 12, 75 | color: "white", 76 | }, 77 | details: { 78 | flex: 5, 79 | flexDirection: "column", 80 | borderTopWidth: StyleSheet.hairlineWidth, 81 | borderBottomWidth: StyleSheet.hairlineWidth, 82 | borderColor: "white", 83 | }, 84 | detailsRow: { 85 | flex: 1, 86 | flexDirection: "row", 87 | alignItems: "center", 88 | justifyContent: "space-between", 89 | }, 90 | detailsRowColumn: { 91 | flex: 1, 92 | flexDirection: "row", 93 | alignItems: "center", 94 | justifyContent: "space-between", 95 | paddingLeft: 5, 96 | paddingRight: 5, 97 | }, 98 | separator: { 99 | height: StyleSheet.hairlineWidth, 100 | backgroundColor: "white", 101 | }, 102 | separatorThin: { 103 | height: StyleSheet.hairlineWidth, 104 | backgroundColor: "#A6A6A6", 105 | }, 106 | propertyText: { 107 | fontSize: 12, 108 | color: "#A6A6A6", 109 | textAlign: "left", 110 | }, 111 | valueText: { 112 | fontSize: 15, 113 | color: "white", 114 | textAlign: "right", 115 | }, 116 | }); 117 | -------------------------------------------------------------------------------- /components/Stock/InfoSlideThree.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, View } from "react-native"; 3 | 4 | export default function InfoSlideThree({ info }) { 5 | return ( 6 | 7 | 8 | 9 | 10 | 50 DAYS MA 11 | 12 | {parseFloat(info["day50MovingAvg"]).toFixed(2) || "--"} 13 | 14 | 15 | 16 | 200 DAYS MA 17 | 18 | {parseFloat(info["day200MovingAvg"]).toFixed(2) || "--"} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 5 DAYS CHANGE(%) 27 | 28 | {parseFloat(info["day5ChangePercent"]).toFixed(2) || "--"} 29 | 30 | 31 | 32 | 30 DAYS CHANGE(%) 33 | 34 | {parseFloat(info["day30ChangePercent"]).toFixed(2) || "--"} 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 6 MONTH CHANGE(%) 43 | 44 | {parseFloat(info["month6ChangePercent"]).toFixed(2) || "--"} 45 | 46 | 47 | 48 | 1 YEAR CHANGE(%) 49 | 50 | {parseFloat(info["year1ChangePercent"]).toFixed(2) || "--"} 51 | 52 | 53 | 54 | 55 | 56 | 57 | ); 58 | } 59 | const styles = StyleSheet.create({ 60 | container: { 61 | flex: 1, 62 | paddingLeft: 10, 63 | paddingRight: 10, 64 | backgroundColor: "black", 65 | }, 66 | nameBlock: { 67 | flex: 1, 68 | paddingTop: 4, 69 | justifyContent: "center", 70 | alignItems: "center", 71 | }, 72 | nameText: { 73 | fontWeight: "bold", 74 | fontSize: 12, 75 | color: "white", 76 | }, 77 | details: { 78 | flex: 5, 79 | flexDirection: "column", 80 | borderTopWidth: StyleSheet.hairlineWidth, 81 | borderBottomWidth: StyleSheet.hairlineWidth, 82 | borderColor: "white", 83 | }, 84 | detailsRow: { 85 | flex: 1, 86 | flexDirection: "row", 87 | alignItems: "center", 88 | justifyContent: "space-between", 89 | }, 90 | detailsRowColumn: { 91 | flex: 1, 92 | flexDirection: "row", 93 | alignItems: "center", 94 | justifyContent: "space-between", 95 | paddingLeft: 5, 96 | paddingRight: 5, 97 | }, 98 | separator: { 99 | height: StyleSheet.hairlineWidth, 100 | backgroundColor: "white", 101 | }, 102 | separatorThin: { 103 | height: StyleSheet.hairlineWidth, 104 | backgroundColor: "#A6A6A6", 105 | }, 106 | propertyText: { 107 | fontSize: 12, 108 | color: "#A6A6A6", 109 | textAlign: "left", 110 | }, 111 | valueText: { 112 | fontSize: 15, 113 | color: "white", 114 | textAlign: "right", 115 | }, 116 | }); 117 | -------------------------------------------------------------------------------- /components/Stock/InfoSlideTwo.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, View } from "react-native"; 3 | 4 | export default function InfoSlideTwo({ info }) { 5 | return ( 6 | 7 | 8 | 9 | 10 | YIELD 11 | 12 | {info["dividendYield"] 13 | ? parseFloat(info["dividendYield"]).toFixed(2) 14 | : "--"} 15 | 16 | 17 | 18 | MKT CAP 19 | 20 | {info["marketcap"] 21 | ? parseFloat(info["marketcap"] / 1000000000).toFixed(2) 22 | : "--"}{" "} 23 | B 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | EPS(est.) 32 | 33 | {info["ttmEPS"] ? parseFloat(info["ttmEPS"]).toFixed(2) : "--"} 34 | 35 | 36 | 37 | PRICE TO SALE 38 | 39 | {info["priceToSales"] 40 | ? parseFloat(info["priceToSales"]).toFixed(2) 41 | : "--"} 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | PRICE TO BOOK 50 | 51 | {info["priceToBook"] 52 | ? parseFloat(info["priceToBook"]).toFixed(2) 53 | : "--"} 54 | 55 | 56 | 57 | PE RATIO 58 | 59 | {info["peRatio"] ? parseFloat(info["peRatio"]).toFixed(2) : "--"} 60 | 61 | 62 | 63 | 64 | 65 | 66 | ); 67 | } 68 | const styles = StyleSheet.create({ 69 | container: { 70 | flex: 1, 71 | paddingLeft: 10, 72 | paddingRight: 10, 73 | backgroundColor: "black", 74 | }, 75 | nameBlock: { 76 | flex: 1, 77 | paddingTop: 4, 78 | justifyContent: "center", 79 | alignItems: "center", 80 | }, 81 | nameText: { 82 | fontWeight: "bold", 83 | fontSize: 12, 84 | color: "white", 85 | }, 86 | details: { 87 | flex: 5, 88 | flexDirection: "column", 89 | borderTopWidth: StyleSheet.hairlineWidth, 90 | borderBottomWidth: StyleSheet.hairlineWidth, 91 | borderColor: "white", 92 | }, 93 | detailsRow: { 94 | flex: 1, 95 | flexDirection: "row", 96 | alignItems: "center", 97 | justifyContent: "space-between", 98 | }, 99 | detailsRowColumn: { 100 | flex: 1, 101 | flexDirection: "row", 102 | alignItems: "center", 103 | justifyContent: "space-between", 104 | paddingLeft: 5, 105 | paddingRight: 5, 106 | }, 107 | separator: { 108 | height: StyleSheet.hairlineWidth, 109 | backgroundColor: "white", 110 | }, 111 | separatorThin: { 112 | height: StyleSheet.hairlineWidth, 113 | backgroundColor: "#A6A6A6", 114 | }, 115 | propertyText: { 116 | fontSize: 12, 117 | color: "#A6A6A6", 118 | textAlign: "left", 119 | }, 120 | valueText: { 121 | fontSize: 15, 122 | color: "white", 123 | textAlign: "right", 124 | }, 125 | }); 126 | -------------------------------------------------------------------------------- /components/Stock/Input.js: -------------------------------------------------------------------------------- 1 | import React, { Component, useState } from "react"; 2 | import { 3 | StyleSheet, 4 | Text, 5 | View, 6 | ScrollView, 7 | TouchableOpacity, 8 | TextInput, 9 | } from "react-native"; 10 | import { Button, Input } from "react-native-elements"; 11 | import axios from "axios"; 12 | 13 | export default function InputForm({ setSelectedStock, selectedStock }) { 14 | const [searchText, setSearchText] = useState(""); 15 | 16 | const fetchStock = async () => { 17 | try { 18 | const res = await axios.get( 19 | `https://sandbox.iexapis.com/stable/stock/${searchText}/chart/1y?token=Tsk_9b260400520a4d23abfe1ef6cb0d3feb` 20 | ); 21 | const infoRes = await axios.get( 22 | `https://sandbox.iexapis.com/stable/stock/${searchText}/advanced-stats?token=Tsk_9b260400520a4d23abfe1ef6cb0d3feb` 23 | ); 24 | setSelectedStock({ 25 | data: res.data, 26 | info: { ...infoRes.data, symbol: searchText.toUpperCase() }, 27 | }); 28 | } catch (error) { 29 | console.log(error); 30 | } 31 | }; 32 | 33 | const handleSubmit = async () => { 34 | searchText && (await fetchStock(searchText)); 35 | setSearchText(""); 36 | }; 37 | 38 | return ( 39 | 53 | 54 | { 56 | setSearchText(textEntry); 57 | }} 58 | style={{ backgroundColor: "transparent" }} 59 | onSubmitEditing={() => handleSubmit()} 60 | color="white" 61 | placeholder="Please enter a symbol" 62 | placeholderTextColor="white" 63 | selectionColor="white" 64 | value={searchText} 65 | /> 66 | 67 | 68 |