Project 1 and 2 are downloadable write-ups. Project 3 and 4 are hands-on builds. Submit according to your instructor’s directions.
Policy analysis with citations; follow the template.
Case study on 2023 banking events; follow the template.
Build a small web app + Google Sheet that fetches a stock’s daily prices and computes monthly returns using GOOGLEFINANCE
. (Corrected instructions.)
// Serves the HTML UI (file name must be lowercase: 'index')
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function fetchStockData(ticker, startDateStr) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Clear previous content (A..F)
sheet.getRange("A1:F1000").clearContent();
// Headers
sheet.getRange("A1").setValue("Date");
sheet.getRange("B1").setValue("Closing Price");
sheet.getRange("C1").setValue("Stock Name");
// Stock name via GOOGLEFINANCE
sheet.getRange("C2").setFormula('=GOOGLEFINANCE("' + ticker + '", "name")');
// Daily close series from startDate to today
// NOTE: "close" returns Date + Close columns
sheet.getRange("A2").setFormula('=GOOGLEFINANCE("' + ticker + '","close","' + startDateStr + '",TODAY(),"daily")');
SpreadsheetApp.flush();
// Pull populated daily values (Date, Close)
var dataRange = sheet.getRange("A2:B1000").getValues();
var valid = dataRange.filter(function(row){ return row[0] && row[1]; });
if (valid.length === 0) {
return "No data returned. Check ticker/date.";
}
// Monthly table headers
sheet.getRange("D1").setValue("Month (YYYY-MM)");
sheet.getRange("E1").setValue("Closing Price");
sheet.getRange("F1").setValue("Monthly Return");
// Last day per month
var monthly = {};
valid.forEach(function(row){
var d = new Date(row[0]);
var p = row[1];
var key = d.getFullYear() + '-' + String(d.getMonth()+1).padStart(2,'0');
monthly[key] = p; // last encountered price becomes "month-end"
});
// Write out months in ascending order
var months = Object.keys(monthly).sort();
var prev = null, r = 2;
months.forEach(function(m){
var price = monthly[m];
sheet.getRange(r, 4).setValue(m);
sheet.getRange(r, 5).setValue(price);
if (prev !== null) {
var ret = ((price - prev) / prev) * 100;
sheet.getRange(r, 6).setValue(ret.toFixed(2) + "%");
}
prev = price; r++;
});
return "OK: Data fetched and monthly returns calculated.";
}
index
)<!DOCTYPE html>
<html>
<head>
<base target="_top">
<title>Stock Data Fetcher</title>
<style>
body{font-family:Arial, sans-serif;margin:20px}
label{display:block;margin-top:10px}
input,button{margin-top:5px}
.footer{margin-top:20px;font-size:12px;color:#666;text-align:center}
</style>
</head>
<body>
<h2>Stock Data Fetcher</h2>
<label for="ticker">Stock Ticker:</label>
<input type="text" id="ticker" placeholder="e.g., AAPL, WMT" />
<label for="startDate">Start Date:</label>
<input type="date" id="startDate" />
<div style="margin-top:10px">
<button onclick="fetchData()">Fetch Data</button>
<button onclick="openGoogleSheet()">Open Google Sheet</button>
</div>
<p id="status"></p>
<script>
function fetchData(){
var ticker = document.getElementById('ticker').value.trim();
var startDate = document.getElementById('startDate').value;
if(!ticker || !startDate){
document.getElementById('status').innerText = "Enter ticker and start date.";
return;
}
google.script.run.withSuccessHandler(function(msg){
document.getElementById('status').innerText = msg;
}).fetchStockData(ticker, startDate);
}
function openGoogleSheet(){
// Replace with your actual Sheet URL (see Troubleshooting)
var sheetUrl = "YOUR_GOOGLE_SHEET_URL";
window.open(sheetUrl, "_blank");
}
</script>
</body>
</html>
index
(lowercase). This must match HtmlService.createHtmlOutputFromFile('index')
.openGoogleSheet()
, replace YOUR_GOOGLE_SHEET_URL
with your sheet’s URL (copy from the browser).GOOGLEFINANCE
returns blanks: verify the ticker and date range; try a different symbol or a closer start date.Deploy a minimal ERC-20 “Campus Dollar (cUSD)” to a local blockchain using Ganache and MetaMask. No Sepolia, no faucets.
ClubStablecoin.sol
→ paste the contract below.// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* Club Stablecoin (simple ERC-20 demo)
* - Owner (deployer) can mint and change owner.
* - Anyone can transfer.
* - Anyone can burn their own tokens.
* - Decimals = 6 (dollar-like: 1.000000)
* NOTE: Local demo only. Not audited. No fees/pausing/blacklists.
*/
contract ClubStablecoin {
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
address public owner;
modifier onlyOwner(){ require(msg.sender == owner, "not owner"); _; }
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
constructor(string memory _name, string memory _symbol, uint8 _decimals){
owner = msg.sender;
emit OwnershipTransferred(address(0), msg.sender);
name = _name;
symbol = _symbol;
decimals = _decimals; // e.g., 6 for $-style 1.000000
}
function balanceOf(address a) public view returns (uint256) { return _balances[a]; }
function allowance(address a, address s) public view returns (uint256) { return _allowances[a][s]; }
function transfer(address to, uint256 amount) public returns (bool) {
_transfer(msg.sender, to, amount); return true;
}
function approve(address spender, uint256 amount) public returns (bool) {
_approve(msg.sender, spender, amount); return true;
}
function transferFrom(address from, address to, uint256 amount) public returns (bool) {
uint256 allowed = _allowances[from][msg.sender];
require(allowed >= amount, "insufficient allowance");
if (allowed != type(uint256).max) {
_allowances[from][msg.sender] = allowed - amount;
emit Approval(from, msg.sender, _allowances[from][msg.sender]);
}
_transfer(from, to, amount); return true;
}
function mint(address to, uint256 amount) public onlyOwner {
require(to != address(0), "mint to zero");
totalSupply += amount; _balances[to] += amount;
emit Transfer(address(0), to, amount);
}
function burn(uint256 amount) public {
uint256 bal = _balances[msg.sender]; require(bal >= amount, "insufficient");
_balances[msg.sender] = bal - amount; totalSupply -= amount;
emit Transfer(msg.sender, address(0), amount);
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "zero owner");
emit OwnershipTransferred(owner, newOwner); owner = newOwner;
}
function _transfer(address from, address to, uint256 amount) internal {
require(to != address(0), "transfer to zero");
uint256 bal = _balances[from]; require(bal >= amount, "insufficient balance");
_balances[from] = bal - amount; _balances[to] += amount;
emit Transfer(from, to, amount);
}
function _approve(address a, address s, uint256 amount) internal {
require(s != address(0), "approve to zero");
_allowances[a][s] = amount; emit Approval(a, s, amount);
}
}
name
: Campus Dollar
symbol
: cUSD
decimals
: 6
mint(<memberAddress>, 1000000)
to send 1.000000 cUSD (6 decimals).transferOwnership()
to next treasurer (or migrate to a Safe on a testnet if you later move beyond Ganache).mint
tx, and wallet balanceCross-listed with FIN 310. Credit cannot be awarded for both ECON 310 and FIN 310.
Section: ECON 310 • 103Z • 25FALL
When/Where: TR 12:30–1:45 PM · Room SIJU137
Instructor: Maggie Foley (mfoley3@ju.edu)
Office: DCOBT 118A · Office Hours: Mon–Thu 2–3 PM & by appt.
Money, Banking, and Financial Markets, Cecchetti & Schoenholtz, 6e (2020), McGraw-Hill Irwin. ISBN 978-1260571363.
Lecture integrates textbook, primary sources, and discussion.
Component | Weight |
---|---|
Two Mid-Term Exams | 40% |
Final Exam | 20% |
Term Project | 10% |
Homework | 20% |
Quizzes (T/F at end of each class; up to 6 misses allowed) | 10% |
Exams: Closed-book/notes; mostly new material but cumulative concepts may reappear.
Quizzes: End of each class; also used for attendance. Up to 6 misses without penalty.
Homework: Due at start of class; legible and done individually unless stated.
Make-ups: With documentation (doctor, coach, Student Life, or university official); notify instructor in advance when possible.
Electronics: Laptops/tablets/phones generally not allowed unless required for an activity.
Extra Credit: Max 5 points across opportunities announced by the instructor.
Administered in class (54 T/F; last 4 ungraded). Solution provided as an HTML/JS page.
Use these for the class MarketWatch game. Open an app, pick candidates in Finviz, then size the trade properly.
MarketWatch game walkthrough
Fundamentals + technical entries, sector mix planner.
Create/join your class game (Virtual Stock Exchange).
Game - FIN310 25 Fall (Live) (have fun)
Intro, short history, role, structure, 2010 chair (Bernanke), JU 2011 visit, videos, mini-quiz.
Fed funds rate, OMOs, discount window, IORB, QE/QT, transmission, statements/minutes, quiz.
Money vs. income/wealth, M0/M1/M2, deposits & money creation, velocity basics, quiz.
Blockchain basics, BTC/ETH, stablecoin types & risks (fiat-backed/crypto/algorithmic), policy, quiz.
Balance-sheet basics, capital & liquidity, FDIC, supervision, lender-of-last-resort. Quiz + examples.
Basel accords, capital & liquidity rules, stress tests, resolution and “living wills.”
T-accounts, money multiplier, currency drain, capital limits; interactive simulator game with quiz.
Debates on TBTF, stablecoins vs banks, and “start-a-bank?” scenarios. Students pick sides; instructor verdicts.
Member-owned credit unions, NCUA insurance, field of membership, local case study on VyStar. Coverage calculator & quiz.
Disclaimer: All materials are developed and provided independently via jufinance.com. Feedback and suggestions are welcome.