diff --git a/docs/en/finance.md b/docs/en/finance.md
index 2e63d0d0cf..cdefe8ecc1 100644
--- a/docs/en/finance.md
+++ b/docs/en/finance.md
@@ -16,6 +16,16 @@ pageClass: routes
+## FX Markets
+
+
+
+| Trading | Infrastructure | Tech and Data | Regulation |
+| ------- | -------------- | ------------- | ---------- |
+| trading | infrastructure | tech-and-data | regulation |
+
+
+
## TokenInsight
### Blogs
diff --git a/docs/finance.md b/docs/finance.md
index 8da5887ad6..e9cc31459c 100644
--- a/docs/finance.md
+++ b/docs/finance.md
@@ -44,6 +44,16 @@ pageClass: routes
+## FX Markets
+
+
+
+| Trading | Infrastructure | Tech and Data | Regulation |
+| ------- | -------------- | ------------- | ---------- |
+| trading | infrastructure | tech-and-data | regulation |
+
+
+
## TokenInsight
### 博客
diff --git a/lib/v2/fx-markets/channel.js b/lib/v2/fx-markets/channel.js
new file mode 100644
index 0000000000..2cd7140961
--- /dev/null
+++ b/lib/v2/fx-markets/channel.js
@@ -0,0 +1,56 @@
+const cheerio = require('cheerio');
+const got = require('@/utils/got');
+const { parseDate } = require('@/utils/parse-date');
+
+module.exports = async (ctx) => {
+ const channel = ctx.params.channel;
+ const link = `https://www.fx-markets.com/${channel}`;
+ const html = (await got(link)).data;
+ const $ = cheerio.load(html);
+ const pageTitle = $('header.select-header > h1').text();
+ const title = `FX-Markets ${pageTitle}`;
+
+ const items = $('div#listings').children();
+ const articles = items
+ .map((i, el) => {
+ const $el = $(el);
+ const $titleEl = $el.find('h5 > a');
+ const articleURL = `https://www.fx-markets.com${$titleEl.attr('href')}`;
+ const articleTitle = $titleEl.attr('title');
+ return {
+ title: articleTitle,
+ link: articleURL,
+ pubDate: parseDate($el.find('time').text()),
+ };
+ })
+ .get();
+
+ const result = await Promise.all(
+ articles.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const res = await got(item.link);
+ const doc = cheerio.load(res.data);
+ // This script holds publish datetime info {"datePublished": "2022-05-12T08:45:04+01:00"}
+ const dateScript = doc('script[type="application/ld+json"]').get()[0].children[0].data;
+ const re = /"datePublished": "(?.*)"/;
+ const dateStr = re.exec(dateScript).groups.dateTimePub;
+ const pubDateTime = parseDate(dateStr, 'YYYY-MM-DDTHH:mm:ssZ');
+ // Exclude hidden print message
+ item.description = doc('div.article-page-body-content:not(.print-access-info)').html();
+ return {
+ title: item.title,
+ link: item.link,
+ description: item.description,
+ // if we fail to get accurate publish date time, show date only from article link on index page.
+ pubDate: pubDateTime ? pubDateTime : item.pubDate,
+ };
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title,
+ link,
+ item: result,
+ };
+};
diff --git a/lib/v2/fx-markets/maintainer.js b/lib/v2/fx-markets/maintainer.js
new file mode 100644
index 0000000000..d564c76968
--- /dev/null
+++ b/lib/v2/fx-markets/maintainer.js
@@ -0,0 +1,3 @@
+module.exports = {
+ '/fx-markets/:channel': ['mikkkee'],
+};
diff --git a/lib/v2/fx-markets/radar.js b/lib/v2/fx-markets/radar.js
new file mode 100644
index 0000000000..68cdeabc7d
--- /dev/null
+++ b/lib/v2/fx-markets/radar.js
@@ -0,0 +1,31 @@
+module.exports = {
+ 'fx-markets.com': {
+ _name: 'FX-Markets',
+ '.': [
+ {
+ title: 'Trading',
+ docs: 'https://docs.rsshub.app/finance.html#fx-markets',
+ source: '/trading',
+ target: '/fx-markets/trading',
+ },
+ {
+ title: 'Infrastructure',
+ docs: 'https://docs.rsshub.app/finance.html#fx-markets',
+ source: '/infrastructure',
+ target: '/fx-markets/infrastructure',
+ },
+ {
+ title: 'Tech and Data',
+ docs: 'https://docs.rsshub.app/finance.html#fx-markets',
+ source: '/tech-and-data',
+ target: '/fx-markets/tech-and-data',
+ },
+ {
+ title: 'Regulation',
+ docs: 'https://docs.rsshub.app/finance.html#fx-markets',
+ source: '/regulation',
+ target: '/fx-markets/regulation',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/fx-markets/router.js b/lib/v2/fx-markets/router.js
new file mode 100644
index 0000000000..df3e882749
--- /dev/null
+++ b/lib/v2/fx-markets/router.js
@@ -0,0 +1,3 @@
+module.exports = (router) => {
+ router.get('/:channel', require('./channel'));
+};