Flutter股市数据获取插件stock_market_data的使用
Flutter股市数据获取插件stock_market_data的使用
简介
stock_market_data
是一个用于获取股票市场基础指标和统计数据的Flutter插件。该插件可以帮助你计算买入并持有策略的年化收益率(CAGR)、最大回撤(Drawdown)和收益风险比(MAR),并且支持添加多种技术指标到股票数据中。
特性
- 计算买入并持有策略的年化收益率(CAGR)、最大回撤(Drawdown)和收益风险比(MAR)
- 支持添加以下技术指标到
YahooFinanceCandleData
:- SMA(简单移动平均线)
- EMA(指数移动平均线)
- RSI(相对强弱指数)
- BB(布林带)
- BOP(平衡量)
- MFI(资金流量指数)
- P(价格)
- STDDEV(标准差)
- VWMA(成交量加权移动平均线)
- %R(威廉指标)
开始使用
添加依赖
在你的 pubspec.yaml
文件中添加 stock_market_data
依赖:
dependencies:
stock_market_data: ^0.0.1
获取买入并持有策略的回测结果
import 'package:stock_market_data/stock_market_data.dart';
void main() async {
BuyAndHoldStrategyResult backTest = await StockMarketDataService().getBackTestResultForSymbol('GOOG');
print('CAGR: ${backTest.cagr}');
print('Max Drawdown: ${backTest.maxDrawdown}');
print('MAR: ${backTest.mar}');
}
获取带有技术指标的K线数据
import 'package:stock_market_data/stock_market_data.dart';
void main() async {
List<YahooFinanceCandleData> prices = await StockMarketDataService().getCandlesWithIndicators('GOOG', ['EMA_20', 'RSI_20']);
for (var price in prices) {
print('Date: ${price.date}, Close: ${price.close}');
print('EMA_20: ${price.indicators['EMA_20']}, RSI_20: ${price.indicators['RSI_20']}');
}
}
获取带有所有技术指标的K线数据
import 'package:stock_market_data/stock_market_data.dart';
void main() async {
List<YahooFinanceCandleData> prices = await StockMarketDataService().getCandlesWithIndicators('GOOG', [
'SMA_20', 'EMA_20', 'RSI_20', 'STDDEV_20', 'VWMA_20', 'BB_20', '%R_20', 'MFI_14', 'BOP_14', 'P_1'
]);
for (var price in prices) {
print('Date: ${price.date}, Close: ${price.close}');
for (var key in price.indicators.keys) {
print('$key: ${price.indicators[key]}');
}
}
}
依赖
yahoo_finance_data_reader
用于从雅虎财经获取数据
示例代码
以下是一个完整的示例代码,展示了如何在Flutter应用中使用 stock_market_data
插件来获取股票数据和显示结果。
import 'package:flutter/material.dart';
import 'package:stock_market_data/stock_market_data.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Stock Market Example'),
),
body: Container(
padding: const EdgeInsets.all(20.0),
child: const SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 355,
width: double.infinity,
child: BuyAndHoldResult(exampleTicker: 'AAPL'),
),
SizedBox(
height: 355,
width: double.infinity,
child: BuyAndHoldResult(exampleTicker: 'VUSA.AS'),
),
SizedBox(
height: 355,
width: double.infinity,
child: BuyAndHoldResult(exampleTicker: 'ES=F, GC=F'),
),
],
),
),
),
);
}
}
class BuyAndHoldResult extends StatefulWidget {
final String exampleTicker;
const BuyAndHoldResult({required this.exampleTicker, super.key});
@override
State<BuyAndHoldResult> createState() => _BuyAndHoldResultState();
}
class _BuyAndHoldResultState extends State<BuyAndHoldResult> {
final TextEditingController controller = TextEditingController(text: '');
BuyAndHoldStrategyResult backTest = BuyAndHoldStrategyResult();
bool loading = true;
String error = '';
@override
void initState() {
super.initState();
controller.text = widget.exampleTicker;
load();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text('Ticker from yahoo finance'),
TextField(
controller: controller,
),
MaterialButton(
onPressed: load,
color: Theme.of(context).primaryColor,
child: const Text('Load'),
),
Expanded(
child: error != ''
? Text('Error: $error')
: loading
? const Center(
child: CircularProgressIndicator(),
)
: Column(
children: [
const SizedBox(height: 20),
_BackTestResult(backTest),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MaterialButton(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
_IndicatorsData(controller.text),
),
),
color: Colors.teal,
child: const Text('Indicators'),
),
const SizedBox(width: 20),
MaterialButton(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
_YearStatsWidget(controller.text),
),
),
color: Colors.orange,
child: const Text('Year stats'),
),
],
)
],
),
),
],
);
}
void load() async {
try {
error = '';
loading = true;
setState(() {});
backTest = await StockMarketDataService().getBackTestResultForSymbol(controller.text);
loading = false;
setState(() {});
} catch (e) {
error = 'Error getting the symbol ${controller.text}:\n $e';
setState(() {});
}
}
}
class _BackTestResult extends StatelessWidget {
final BuyAndHoldStrategyResult backTest;
const _BackTestResult(this.backTest);
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
children: [
const Expanded(child: Text('CAGR')),
Expanded(child: Text(backTest.cagr.toStringAsFixed(2))),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Expanded(child: Text('Max Drawdown')),
Expanded(child: Text(backTest.maxDrawdown.toStringAsFixed(2))),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Expanded(child: Text('MAR')),
Expanded(child: Text(backTest.mar.toStringAsFixed(2))),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Expanded(child: Text('Trading years')),
Expanded(child: Text(backTest.tradingYears.toStringAsFixed(2))),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Expanded(child: Text('Start date')),
Expanded(child: Text(backTest.startDate.toString())),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Expanded(child: Text('End date')),
Expanded(child: Text(backTest.endDate.toString())),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Expanded(child: Text('Current drawdown')),
Expanded(child: Text(backTest.currentDrawdown.toStringAsFixed(2))),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Expanded(child: Text('End price')),
Expanded(child: Text(backTest.endPrice.toStringAsFixed(2))),
],
),
],
);
}
}
class _YearStatsWidget extends StatefulWidget {
final String symbol;
const _YearStatsWidget(this.symbol);
@override
State<_YearStatsWidget> createState() => _YearStatsWidgetState();
}
class _YearStatsWidgetState extends State<_YearStatsWidget> {
@override
void initState() {
super.initState();
load();
}
List<YahooFinanceCandleData> prices = [];
List<YearlyStats> yearlyStats = [];
void load() async {
YahooFinanceResponse response = await const YahooFinanceDailyReader().getDailyDTOs(widget.symbol);
prices = response.candlesData;
yearlyStats = YearlyCalculations.calculate(prices);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Year stats'),
),
body: Column(
children: [
const Row(
children: [
Expanded(child: Text('Year')),
Expanded(child: Text('Variation')),
Expanded(child: Text('Drawdown')),
],
),
const SizedBox(height: 10),
Expanded(
child: ListView.builder(
itemCount: yearlyStats.length,
itemBuilder: (context, index) {
final YearlyStats currentYearlyStat = yearlyStats[index];
return Row(
children: [
Expanded(child: Text(currentYearlyStat.year.toString())),
Expanded(child: Text(currentYearlyStat.variation.toStringAsFixed(2))),
Expanded(child: Text(currentYearlyStat.drawdown.toStringAsFixed(2))),
],
);
},
),
),
],
),
);
}
}
class _IndicatorsData extends StatefulWidget {
final String symbol;
const _IndicatorsData(this.symbol);
@override
State<_IndicatorsData> createState() => _IndicatorsDataState();
}
class _IndicatorsDataState extends State<_IndicatorsData> {
final TextEditingController indicatorsController = TextEditingController(
text:
'SMA_20,EMA_20,RSI_20,STDDEV_20,VWMA_20,BB_20,%R_20,MFI_14,BOP_14,P_1',
);
List<YahooFinanceCandleData> prices = [];
void load() async {
prices = await StockMarketDataService().getCandlesWithIndicators(
widget.symbol,
indicatorsController.text.split(','),
);
// Reverse to show in a list
prices = prices.reversed.toList();
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Indicators'),
),
body: ListView.builder(
itemCount: prices.length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
margin: const EdgeInsets.all(10),
child: Column(
children: [
const Text('Indicators'),
TextField(
controller: indicatorsController,
maxLines: 3,
),
MaterialButton(
onPressed: load,
color: Theme.of(context).primaryColor,
child: const Text('Load'),
),
],
),
);
}
final i = index - 1;
return _PriceWithIndicators(prices[i]);
},
),
);
}
}
class _PriceWithIndicators extends StatelessWidget {
final YahooFinanceCandleData candle;
const _PriceWithIndicators(this.candle);
@override
Widget build(BuildContext context) {
return Card(
child: Container(
margin: const EdgeInsets.all(10),
child: Column(
children: [
Text('Date: ${candle.date}'),
Text('Close: ${candle.close}'),
Column(
children: candle.indicators.keys
.map((key) => Text('$key: ${candle.indicators[key]?.toStringAsFixed(2)}'))
.toList())
],
),
),
);
}
}
在Pub.dev上点赞
如果你喜欢这个插件,请在 Pub.dev 上给它点赞和支持!
发布插件到Pub.dev
如果你想发布这个插件到Pub.dev,可以使用以下命令:
dart pub publish
希望这个插件能帮助你在Flutter应用中更方便地处理股票市场数据!如果有任何问题或建议,请随时联系我。
更多关于Flutter股市数据获取插件stock_market_data的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter股市数据获取插件stock_market_data的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用stock_market_data
插件来获取股市数据的示例代码。假设你已经在你的Flutter项目中添加了stock_market_data
依赖。
首先,确保在你的pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
stock_market_data: ^最新版本号 # 替换为实际的最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,我们编写一个简单的Flutter应用来展示如何使用stock_market_data
插件获取股市数据。
main.dart
import 'package:flutter/material.dart';
import 'package:stock_market_data/stock_market_data.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Stock Market Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: StockMarketDataScreen(),
);
}
}
class StockMarketDataScreen extends StatefulWidget {
@override
_StockMarketDataScreenState createState() => _StockMarketDataScreenState();
}
class _StockMarketDataScreenState extends State<StockMarketDataScreen> {
String stockSymbol = 'AAPL'; // 示例股票代码:苹果公司
String stockData = '';
@override
void initState() {
super.initState();
fetchStockData();
}
void fetchStockData() async {
try {
final stockMarketData = StockMarketData();
final data = await stockMarketData.getStockMarketData(stockSymbol);
// 假设返回的数据包含一个名为'price'的字段
setState(() {
stockData = 'Price: \$${data['price']}';
});
} catch (e) {
print('Error fetching stock data: $e');
setState(() {
stockData = 'Error fetching stock data';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Stock Market Data'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Stock Symbol: $stockSymbol',
style: TextStyle(fontSize: 20),
),
SizedBox(height: 20),
Text(
stockData,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
],
),
),
);
}
}
注意事项
-
API限制和权限:某些股市数据API可能有访问限制或需要API密钥。请确保你了解并遵守你使用的特定API的条款和条件。
-
错误处理:上面的代码只简单地打印了错误消息。在实际应用中,你可能需要更详细的错误处理逻辑,例如向用户显示友好的错误消息。
-
数据字段:上面的代码假设返回的数据包含一个名为
price
的字段。你需要根据你使用的API的文档来调整这部分代码。 -
依赖更新:确保你的
stock_market_data
插件是最新版本,并查阅其文档以获取最新的使用方法和API变化。
这个示例展示了如何使用stock_market_data
插件在Flutter应用中获取并展示股市数据。根据你的具体需求,你可能需要进一步定制和扩展这个示例。