const apiKey = document.querySelector('#api-key') as HTMLInputElement; { const storedApiKey = localStorage.getItem('fio-api-key'); if (storedApiKey) apiKey.value = storedApiKey; } document.querySelector('#fetch')!.addEventListener('click', async () => { const loader = document.querySelector('#loader') as HTMLElement; loader.innerHTML = ''; loader.style.display = 'block'; try { await renderLedger(apiKey.value); localStorage.setItem('fio-api-key', apiKey.value); } catch (e) { console.error(e); } loader.style.display = 'none'; }); async function getPrices(): Promise> { const allPrices: Price[] = await fetchJSON('https://refined-prun.github.io/refined-prices/all.json'); const priceMap: Record = {}; for (const price of allPrices) if (price.ExchangeCode === 'IC1') priceMap[price.MaterialTicker] = price.VWAP30D; console.log(priceMap); return priceMap; } const pricePromise = getPrices(); const ledger = document.querySelector('textarea#ledger') as HTMLTextAreaElement; async function renderLedger(apiKey: string): Promise { ledger.style.display = 'none'; ledger.value = 'Time,Mat,Quantity,Actual Unit Price,Discounted Unit Price,Gateway,Debit,Credit,Contract ID\n'; const prices = await pricePromise; const contracts: Contract[] = await fetchJSON('https://rest.fnar.net/contract/allcontracts', {headers: {'Authorization': apiKey}}); contracts.sort((a, b) => a.DateEpochMs - b.DateEpochMs); for (const contract of contracts) { if (contract.PartnerCompanyCode === null || contract.PartnerName.endsWith(' Commodity Exchange')) continue; // NPC contract contract.Conditions.sort((a, b) => a.ConditionIndex - b.ConditionIndex); for (let i = 0; i < contract.Conditions.length; i++) { const condition = contract.Conditions[i]; if ((contract.Party !== condition.Party && condition.Type === 'DELIVERY') || // counterparty is delivering (contract.Party === condition.Party && condition.Type === 'COMEX_PURCHASE_PICKUP')) { // we are picking up const time = new Date(contract.DateEpochMs).toISOString(); const mat = condition.MaterialTicker; const quantity = condition.MaterialAmount; const totalPrice = contract.Conditions[i-1].Amount; ledger.value += `${time},${mat},${quantity},${prices[mat]},${totalPrice / quantity},,${totalPrice},,${contract.ContractLocalId}\n`; } else continue; } } ledger.style.display = 'block'; } document.querySelector('#copy')!.addEventListener('click', () => { navigator.clipboard.writeText(ledger.value); }); async function fetchJSON(url: string, options: RequestInit = {}): Promise { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); const doc = await fetch(url, {...options, signal: controller.signal}).then((r) => r.json()); clearTimeout(timeoutId); return doc; } interface Contract { Conditions: Array; ContractLocalId: string; Party: string; Status: string; PartnerName: string; PartnerCompanyCode: string; DateEpochMs: number; } interface ContractCondition { ConditionIndex: number; Type: string; Party: string; MaterialTicker: string; MaterialAmount: number; Amount: number; Currency: string; } interface Price { MaterialTicker: string ExchangeCode: string VWAP30D: number | null }